mtimeout.1: Use correct dash for number ranges.
[misc] / gai.c
1 #define _GNU_SOURCE
2
3 #include <ctype.h>
4 #include <errno.h>
5 #include <limits.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include <getopt.h>
11
12 #include <netdb.h>
13
14 struct nameval { const char *name; int val; };
15 const char *prog = "<unset>";
16
17 static int parseint(const char *s, const char *what)
18 {
19 char *q;
20 unsigned long i;
21 int e = errno;
22
23 if (!isdigit((unsigned char)*s)) goto fail;
24 errno = 0;
25 i = strtoul(s, &q, 0);
26 if (errno || *q || i > INT_MAX) goto fail;
27 errno = e;
28 return ((int)i);
29
30 fail:
31 fprintf(stderr, "%s: bad numeric %s `%s'\n", prog, what, s);
32 exit(1);
33 }
34
35 static int lookup(const char *name, const char *what,
36 const struct nameval *nv)
37 {
38 if (isdigit((unsigned char)*name))
39 return (parseint(name, what));
40 for (; nv->name; nv++)
41 if (strcmp(nv->name, name) == 0) return nv->val;
42 fprintf(stderr, "%s: unknown %s `%s'\n", prog, what, name);
43 exit(1);
44 }
45
46 static const char *rlookup(int val, const char *what,
47 const struct nameval *nv)
48 {
49 static char buf[32];
50 for (; nv->name; nv++)
51 if (nv->val == val) return (nv->name);
52 sprintf(buf, "%s#%d", what, val);
53 return (buf);
54 }
55
56 static const struct nameval familymap[] = {
57 { "unspec", AF_UNSPEC },
58 { "inet", AF_INET },
59 { "inet6", AF_INET6 },
60 { 0 }
61 };
62
63 static const struct nameval typemap[] = {
64 { "any", 0 },
65 { "stream", SOCK_STREAM },
66 { "dgram", SOCK_DGRAM },
67 { "raw", SOCK_RAW },
68 { 0 }
69 };
70
71 static void usage(FILE *fp)
72 {
73 fprintf(fp,
74 "Usage: %s "
75 "[-CNacgimnsuv] [-f FAMILY] [-p PROTOCOL] [-t TYPE] "
76 "NAME [SERVICE]\n",
77 prog);
78 }
79
80 static void help(FILE *fp)
81 {
82 usage(fp); fputs("\n\
83 Options:\n\
84 \n\
85 -a plain v4 also (with -m) -n numeric host\n\
86 -c canonify name -N numeric service\n\
87 -C canonify to IDN (with -c) -s allow unassigned codepoints\n\
88 -g families with configured addrs -u check result is STD3 hostname\n\
89 -i convert to IDN -v passive\n\
90 -m v6-mapped v4 addresses\n\
91 \n\
92 -f unspec|inet|inet6 NAME -- hostname or `-' for none\n\
93 -p PROTOCOL -- /etc/protocols SERVICE -- number or /etc/services\n\
94 -t any|stream|dgram|raw\n\
95 ", fp);
96 }
97
98 int main(int argc, char *argv[])
99 {
100 struct addrinfo *ai, hint = { .ai_family = AF_UNSPEC };
101 const char *name;
102 const char *serv = 0;
103 char namebuf[NI_MAXHOST], servbuf[NI_MAXSERV];
104 int err;
105
106 prog = strrchr(argv[0], '/');
107 if (prog) prog++;
108 else prog = argv[0];
109
110 for (;;) {
111 int opt = getopt(argc, argv, "hf:t:p:nNcvgamiCus");
112 if (opt < 0) break;
113 switch (opt) {
114 case 'h': help(stdout); exit(0);
115 case 'f':
116 hint.ai_family = lookup(optarg, "family", familymap);
117 break;
118 case 't':
119 hint.ai_socktype = lookup(optarg, "type", typemap);
120 break;
121 case 'p':
122 if (isdigit((unsigned char)*optarg))
123 hint.ai_protocol = parseint(optarg, "protocol");
124 else {
125 struct protoent *p = getprotobyname(optarg);
126 if (!p) {
127 fprintf(stderr, "%s: unknown protocol `%s'\n", prog, optarg);
128 exit(1);
129 }
130 hint.ai_protocol = p->p_proto;
131 }
132 break;
133 case 'C': hint.ai_flags |= AI_CANONIDN; break;
134 case 'N': hint.ai_flags |= AI_NUMERICSERV; break;
135 case 'a': hint.ai_flags |= AI_ALL; break;
136 case 'c': hint.ai_flags |= AI_CANONNAME; break;
137 case 'g': hint.ai_flags |= AI_ADDRCONFIG; break;
138 case 'i': hint.ai_flags |= AI_IDN; break;
139 case 'm': hint.ai_flags |= AI_V4MAPPED; break;
140 case 'n': hint.ai_flags |= AI_NUMERICHOST; break;
141 case 's': hint.ai_flags |= AI_IDN_USE_STD3_ASCII_RULES; break;
142 case 'u': hint.ai_flags |= AI_IDN_ALLOW_UNASSIGNED; break;
143 case 'v': hint.ai_flags |= AI_PASSIVE; break;
144 default: usage(stderr); exit(1);
145 }
146 }
147
148 argv += optind;
149 if (!*argv) { usage(stderr); exit(1); } name = *argv++;
150 if (*argv) { serv = *argv++; }
151 if (*argv) { usage(stderr); exit(1); }
152
153 if (strcmp(name, "-") == 0) name = 0;
154
155 if ((err = getaddrinfo(name, serv, &hint, &ai)) != 0) {
156 fprintf(stderr, "%s: %s\n", prog, gai_strerror(err));
157 exit(1);
158 }
159
160 for (; ai; ai = ai->ai_next) {
161 if (ai->ai_canonname) printf("[%s]\n", ai->ai_canonname);
162 fputs(rlookup(ai->ai_family, "family", familymap), stdout);
163 fputc(' ', stdout);
164 fputs(rlookup(ai->ai_socktype, "type", typemap), stdout);
165 fputc(' ', stdout);
166 if ((err = getnameinfo(ai->ai_addr, ai->ai_addrlen,
167 namebuf, sizeof(namebuf),
168 servbuf, sizeof(servbuf),
169 (NI_NUMERICHOST | NI_NUMERICSERV |
170 (ai->ai_socktype == SOCK_DGRAM ?
171 NI_DGRAM : 0)))) != 0)
172 printf("(error: %s)", gai_strerror(err));
173 else
174 printf("%s %s", namebuf, servbuf);
175 fputc('\n', stdout);
176 }
177
178 freeaddrinfo(ai);
179
180 return (0);
181 }