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 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 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 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 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 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