1#include <sys/socket.h>
2#include <netinet/in.h>
3#include <netdb.h>
4#include <ctype.h>
5#include <string.h>
6#include <fcntl.h>
7#include <errno.h>
8#include "lookup.h"
9#include "stdio_impl.h"
10
11int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int socktype, int flags)
12{
13	char line[128];
14	int cnt = 0;
15	char *p, *z = "";
16	unsigned long port = 0;
17
18	switch (socktype) {
19	case SOCK_STREAM:
20		switch (proto) {
21		case 0:
22			proto = IPPROTO_TCP;
23		case IPPROTO_TCP:
24			break;
25		default:
26			return EAI_SERVICE;
27		}
28		break;
29	case SOCK_DGRAM:
30		switch (proto) {
31		case 0:
32			proto = IPPROTO_UDP;
33		case IPPROTO_UDP:
34			break;
35		default:
36			return EAI_SERVICE;
37		}
38	case 0:
39		break;
40	default:
41		if (name) return EAI_SERVICE;
42		buf[0].port = 0;
43		buf[0].proto = proto;
44		buf[0].socktype = socktype;
45		return 1;
46	}
47
48	if (name) {
49		if (!*name) return EAI_SERVICE;
50		port = strtoul(name, &z, 10);
51	}
52	if (!*z) {
53		if (port > 65535) return EAI_SERVICE;
54		if (proto != IPPROTO_UDP) {
55			buf[cnt].port = port;
56			buf[cnt].socktype = SOCK_STREAM;
57			buf[cnt++].proto = IPPROTO_TCP;
58		}
59		if (proto != IPPROTO_TCP) {
60			buf[cnt].port = port;
61			buf[cnt].socktype = SOCK_DGRAM;
62			buf[cnt++].proto = IPPROTO_UDP;
63		}
64		return cnt;
65	}
66
67	if (flags & AI_NUMERICSERV) return EAI_SERVICE;
68
69	size_t l = strlen(name);
70
71	unsigned char _buf[1032];
72	FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf);
73	if (!f) switch (errno) {
74	case ENOENT:
75	case ENOTDIR:
76	case EACCES:
77		return EAI_SERVICE;
78	default:
79		return EAI_SYSTEM;
80	}
81
82	while (fgets(line, sizeof line, f) && cnt < MAXSERVS) {
83		if ((p=strchr(line, '#'))) *p++='\n', *p=0;
84
85		/* Find service name */
86		for(p=line; (p=strstr(p, name)); p++) {
87			if (p>line && !isspace(p[-1])) continue;
88			if (p[l] && !isspace(p[l])) continue;
89			break;
90		}
91		if (!p) continue;
92
93		/* Skip past canonical name at beginning of line */
94		for (p=line; *p && !isspace(*p); p++);
95
96		port = strtoul(p, &z, 10);
97		if (port > 65535 || z==p) continue;
98		if (!strncmp(z, "/udp", 4)) {
99			if (proto == IPPROTO_TCP) continue;
100			buf[cnt].port = port;
101			buf[cnt].socktype = SOCK_DGRAM;
102			buf[cnt++].proto = IPPROTO_UDP;
103		}
104		if (!strncmp(z, "/tcp", 4)) {
105			if (proto == IPPROTO_UDP) continue;
106			buf[cnt].port = port;
107			buf[cnt].socktype = SOCK_STREAM;
108			buf[cnt++].proto = IPPROTO_TCP;
109		}
110	}
111	__fclose_ca(f);
112	return cnt > 0 ? cnt : EAI_SERVICE;
113}
114