nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* source: xio-ip.c */ |
2 | /* Copyright Gerhard Rieger */ |
||
3 | /* Published under the GNU General Public License V.2, see file COPYING */ |
||
4 | |||
5 | /* this file contains the source for IP related functions */ |
||
6 | |||
7 | #include "xiosysincludes.h" |
||
8 | |||
9 | #if _WITH_IP4 || _WITH_IP6 |
||
10 | |||
11 | #include "xioopen.h" |
||
12 | |||
13 | #include "xio-ascii.h" |
||
14 | #include "xio-socket.h" |
||
15 | #include "xio-ip.h" |
||
16 | #include "xio-ip6.h" |
||
17 | |||
18 | |||
19 | #if WITH_IP4 || WITH_IP6 |
||
20 | |||
21 | #ifdef IP_OPTIONS |
||
22 | const struct optdesc opt_ip_options = { "ip-options", "ipoptions", OPT_IP_OPTIONS, GROUP_SOCK_IP, PH_PASTSOCKET,TYPE_BIN, OFUNC_SOCKOPT_APPEND, SOL_IP, IP_OPTIONS }; |
||
23 | #endif |
||
24 | #ifdef IP_PKTINFO |
||
25 | const struct optdesc opt_ip_pktinfo = { "ip-pktinfo", "pktinfo", OPT_IP_PKTINFO, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_PKTINFO }; |
||
26 | #endif |
||
27 | #ifdef IP_RECVTOS |
||
28 | const struct optdesc opt_ip_recvtos = { "ip-recvtos", "recvtos", OPT_IP_RECVTOS, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVTOS }; |
||
29 | #endif |
||
30 | #ifdef IP_RECVTTL /* -Cygwin */ |
||
31 | const struct optdesc opt_ip_recvttl = { "ip-recvttl", "recvttl", OPT_IP_RECVTTL, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVTTL }; |
||
32 | #endif |
||
33 | #ifdef IP_RECVOPTS |
||
34 | const struct optdesc opt_ip_recvopts= { "ip-recvopts","recvopts", OPT_IP_RECVOPTS,GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVOPTS }; |
||
35 | #endif |
||
36 | #ifdef IP_RETOPTS |
||
37 | const struct optdesc opt_ip_retopts = { "ip-retopts", "retopts", OPT_IP_RETOPTS, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RETOPTS }; |
||
38 | #endif |
||
39 | const struct optdesc opt_ip_tos = { "ip-tos", "tos", OPT_IP_TOS, GROUP_SOCK_IP, PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_TOS }; |
||
40 | const struct optdesc opt_ip_ttl = { "ip-ttl", "ttl", OPT_IP_TTL, GROUP_SOCK_IP, PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_TTL }; |
||
41 | #ifdef IP_HDRINCL |
||
42 | const struct optdesc opt_ip_hdrincl = { "ip-hdrincl", "hdrincl", OPT_IP_HDRINCL, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_HDRINCL }; |
||
43 | #endif |
||
44 | #ifdef IP_RECVERR |
||
45 | const struct optdesc opt_ip_recverr = { "ip-recverr", "recverr", OPT_IP_RECVERR, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVERR }; |
||
46 | #endif |
||
47 | #ifdef IP_MTU_DISCOVER |
||
48 | const struct optdesc opt_ip_mtu_discover={"ip-mtu-discover","mtudiscover",OPT_IP_MTU_DISCOVER,GROUP_SOCK_IP,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_IP,IP_MTU_DISCOVER }; |
||
49 | #endif |
||
50 | #ifdef IP_MTU |
||
51 | const struct optdesc opt_ip_mtu = { "ip-mtu", "mtu", OPT_IP_MTU, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_MTU }; |
||
52 | #endif |
||
53 | #ifdef IP_FREEBIND |
||
54 | const struct optdesc opt_ip_freebind= { "ip-freebind","freebind", OPT_IP_FREEBIND,GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_FREEBIND }; |
||
55 | #endif |
||
56 | #ifdef IP_ROUTER_ALERT |
||
57 | const struct optdesc opt_ip_router_alert={"ip-router-alert","routeralert",OPT_IP_ROUTER_ALERT,GROUP_SOCK_IP,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_IP,IP_ROUTER_ALERT}; |
||
58 | #endif |
||
59 | /* following: Linux allows int but OpenBSD reqs char/byte */ |
||
60 | const struct optdesc opt_ip_multicast_ttl={"ip-multicast-ttl","multicastttl",OPT_IP_MULTICAST_TTL,GROUP_SOCK_IP,PH_PASTSOCKET,TYPE_BYTE,OFUNC_SOCKOPT,SOL_IP,IP_MULTICAST_TTL}; |
||
61 | /* following: Linux allows int but OpenBSD reqs char/byte */ |
||
62 | const struct optdesc opt_ip_multicast_loop={"ip-multicast-loop","multicastloop",OPT_IP_MULTICAST_LOOP,GROUP_SOCK_IP,PH_PASTSOCKET,TYPE_BYTE,OFUNC_SOCKOPT,SOL_IP,IP_MULTICAST_LOOP}; |
||
63 | const struct optdesc opt_ip_multicast_if ={"ip-multicast-if", "multicast-if", OPT_IP_MULTICAST_IF, GROUP_SOCK_IP,PH_PASTSOCKET,TYPE_IP4NAME,OFUNC_SOCKOPT,SOL_IP,IP_MULTICAST_IF}; |
||
64 | #ifdef IP_PKTOPTIONS |
||
65 | const struct optdesc opt_ip_pktoptions = { "ip-pktoptions", "pktopts", OPT_IP_PKTOPTIONS, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_PKTOPTIONS }; |
||
66 | #endif |
||
67 | #ifdef IP_ADD_MEMBERSHIP |
||
68 | const struct optdesc opt_ip_add_membership = { "ip-add-membership", "membership",OPT_IP_ADD_MEMBERSHIP, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IP, IP_ADD_MEMBERSHIP }; |
||
69 | #endif |
||
70 | #ifdef IP_RECVDSTADDR |
||
71 | const struct optdesc opt_ip_recvdstaddr = { "ip-recvdstaddr", "recvdstaddr",OPT_IP_RECVDSTADDR, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVDSTADDR }; |
||
72 | #endif |
||
73 | #ifdef IP_RECVIF |
||
74 | const struct optdesc opt_ip_recvif = { "ip-recvif", "recvdstaddrif",OPT_IP_RECVIF, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVIF }; |
||
75 | #endif |
||
76 | |||
77 | #if HAVE_RESOLV_H |
||
78 | const struct optdesc opt_res_debug = { "res-debug", NULL, OPT_RES_DEBUG, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.res_opts), XIO_SIZEOF(para.socket.ip.res_opts), RES_DEBUG }; |
||
79 | const struct optdesc opt_res_aaonly = { "res-aaonly", "aaonly", OPT_RES_AAONLY, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.res_opts), XIO_SIZEOF(para.socket.ip.res_opts), RES_AAONLY }; |
||
80 | const struct optdesc opt_res_usevc = { "res-usevc", "usevc", OPT_RES_USEVC, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.res_opts), XIO_SIZEOF(para.socket.ip.res_opts), RES_USEVC }; |
||
81 | const struct optdesc opt_res_primary = { "res-primary", "primary", OPT_RES_PRIMARY, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.res_opts), XIO_SIZEOF(para.socket.ip.res_opts), RES_PRIMARY }; |
||
82 | const struct optdesc opt_res_igntc = { "res-igntc", "igntc", OPT_RES_IGNTC, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.res_opts), XIO_SIZEOF(para.socket.ip.res_opts), RES_IGNTC }; |
||
83 | const struct optdesc opt_res_recurse = { "res-recurse", "recurse", OPT_RES_RECURSE, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.res_opts), XIO_SIZEOF(para.socket.ip.res_opts), RES_RECURSE }; |
||
84 | const struct optdesc opt_res_defnames = { "res-defnames", "defnames", OPT_RES_DEFNAMES, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.res_opts), XIO_SIZEOF(para.socket.ip.res_opts), RES_DEFNAMES }; |
||
85 | const struct optdesc opt_res_stayopen = { "res-stayopen", "stayopen", OPT_RES_STAYOPEN, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.res_opts), XIO_SIZEOF(para.socket.ip.res_opts), RES_STAYOPEN }; |
||
86 | const struct optdesc opt_res_dnsrch = { "res-dnsrch", "dnsrch", OPT_RES_DNSRCH, GROUP_SOCK_IP, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.res_opts), XIO_SIZEOF(para.socket.ip.res_opts), RES_DNSRCH }; |
||
87 | #endif /* HAVE_RESOLV_H */ |
||
88 | |||
89 | #endif /* WITH_IP4 || WITH_IP6 */ |
||
90 | |||
91 | |||
92 | #if HAVE_RESOLV_H |
||
93 | int Res_init(void) { |
||
94 | int result; |
||
95 | Debug("res_init()"); |
||
96 | result = res_init(); |
||
97 | Debug1("res_init() -> %d", result); |
||
98 | return result; |
||
99 | } |
||
100 | #endif /* HAVE_RESOLV_H */ |
||
101 | |||
102 | #if HAVE_RESOLV_H |
||
103 | unsigned long res_opts() { |
||
104 | return _res.options; |
||
105 | } |
||
106 | #endif /* HAVE_RESOLV_H */ |
||
107 | |||
108 | /* the ultimate(?) socat resolver function |
||
109 | node: the address to be resolved; supported forms: |
||
110 | 1.2.3.4 (IPv4 address) |
||
111 | [::2] (IPv6 address) |
||
112 | hostname (hostname resolving to IPv4 or IPv6 address) |
||
113 | hostname.domain (fq hostname resolving to IPv4 or IPv6 address) |
||
114 | service: the port specification; may be numeric or symbolic |
||
115 | family: PF_INET, PF_INET6, or PF_UNSPEC permitting both |
||
116 | socktype: SOCK_STREAM, SOCK_DGRAM |
||
117 | protocol: IPPROTO_UDP, IPPROTO_TCP |
||
118 | sau: an uninitialized storage for the resulting socket address |
||
119 | returns: STAT_OK, STAT_RETRYLATER |
||
120 | */ |
||
121 | int xiogetaddrinfo(const char *node, const char *service, |
||
122 | int family, int socktype, int protocol, |
||
123 | union sockaddr_union *sau, socklen_t *socklen, |
||
124 | unsigned long res_opts0, unsigned long res_opts1) { |
||
125 | int port = -1; /* port number in network byte order */ |
||
126 | char *numnode = NULL; |
||
127 | size_t nodelen; |
||
128 | unsigned long save_res_opts = 0; |
||
129 | #if HAVE_GETADDRINFO |
||
130 | struct addrinfo hints = {0}; |
||
131 | struct addrinfo *res = NULL; |
||
132 | #else /* HAVE_PROTOTYPE_LIB_getipnodebyname || nothing */ |
||
133 | struct hostent *host; |
||
134 | #endif |
||
135 | int error_num; |
||
136 | |||
137 | #if HAVE_RESOLV_H |
||
138 | if (res_opts0 | res_opts1) { |
||
139 | if (!(_res.options & RES_INIT)) { |
||
140 | Res_init(); /*!!! returns -1 on error */ |
||
141 | } |
||
142 | save_res_opts = _res.options; |
||
143 | _res.options &= ~res_opts0; |
||
144 | _res.options |= res_opts1; |
||
145 | Debug2("changed _res.options from 0x%lx to 0x%lx", |
||
146 | save_res_opts, _res.options); |
||
147 | } |
||
148 | #endif /* HAVE_RESOLV_H */ |
||
149 | memset(sau, 0, *socklen); |
||
150 | sau->soa.sa_family = family; |
||
151 | |||
152 | if (service && service[0]=='\0') { |
||
153 | Error("empty port/service"); |
||
154 | } |
||
155 | /* if service is numeric we don't want to have a lookup (might take long |
||
156 | with NIS), so we handle this specially */ |
||
157 | if (service && isdigit(service[0]&0xff)) { |
||
158 | char *extra; |
||
159 | port = htons(strtoul(service, &extra, 0)); |
||
160 | if (*extra != '\0') { |
||
161 | Warn2("xiogetaddrinfo(, \"%s\", ...): extra trailing data \"%s\"", |
||
162 | service, extra); |
||
163 | } |
||
164 | service = NULL; |
||
165 | } |
||
166 | |||
167 | /* the resolver functions might handle numeric forms of node names by |
||
168 | reverse lookup, that's not what we want. |
||
169 | So we detect these and handle them specially */ |
||
170 | if (node && isdigit(node[0]&0xff)) { |
||
171 | #if HAVE_GETADDRINFO |
||
172 | hints.ai_flags |= AI_NUMERICHOST; |
||
173 | #endif /* HAVE_GETADDRINFO */ |
||
174 | if (family == PF_UNSPEC) { |
||
175 | family = PF_INET; |
||
176 | #if HAVE_GETADDRINFO |
||
177 | } else if (family == PF_INET6) { |
||
178 | /* map "explicitely" into IPv6 address space; getipnodebyname() does |
||
179 | this with AI_V4MAPPED, but not getaddrinfo() */ |
||
180 | if ((numnode = Malloc(strlen(node)+7+1)) == NULL) { |
||
181 | #if HAVE_RESOLV_H |
||
182 | if (res_opts0 | res_opts1) { |
||
183 | _res.options = (_res.options & (~res_opts0&~res_opts1) | |
||
184 | save_res_opts& ( res_opts0| res_opts1)); |
||
185 | } |
||
186 | #endif |
||
187 | return STAT_NORETRY; |
||
188 | } |
||
189 | sprintf(numnode, "::ffff:%s", node); |
||
190 | node = numnode; |
||
191 | hints.ai_flags |= AI_NUMERICHOST; |
||
192 | #endif /* HAVE_GETADDRINFO */ |
||
193 | } |
||
194 | #if WITH_IP6 |
||
195 | } else if (node && node[0] == '[' && node[(nodelen=strlen(node))-1]==']') { |
||
196 | if ((numnode = Malloc(nodelen-1)) == NULL) { |
||
197 | #if HAVE_RESOLV_H |
||
198 | if (res_opts0 | res_opts1) { |
||
199 | _res.options = (_res.options & (~res_opts0&~res_opts1) | |
||
200 | save_res_opts& ( res_opts0| res_opts1)); |
||
201 | } |
||
202 | #endif |
||
203 | return STAT_NORETRY; |
||
204 | } |
||
205 | strncpy(numnode, node+1, nodelen-2); /* ok */ |
||
206 | numnode[nodelen-2] = '\0'; |
||
207 | node = numnode; |
||
208 | #if HAVE_GETADDRINFO |
||
209 | hints.ai_flags |= AI_NUMERICHOST; |
||
210 | #endif /* HAVE_GETADDRINFO */ |
||
211 | if (family == PF_UNSPEC) family = PF_INET6; |
||
212 | #endif /* WITH_IP6 */ |
||
213 | } |
||
214 | |||
215 | #if HAVE_GETADDRINFO |
||
216 | if (node != NULL || service != NULL) { |
||
217 | struct addrinfo *record; |
||
218 | |||
219 | if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM) { |
||
220 | /* actual socket type value is not supported - fallback to a good one */ |
||
221 | socktype = SOCK_DGRAM; |
||
222 | } |
||
223 | if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP) { |
||
224 | /* actual protocol value is not supported - fallback to a good one */ |
||
225 | if (socktype == SOCK_DGRAM) { |
||
226 | protocol = IPPROTO_UDP; |
||
227 | } else { |
||
228 | protocol = IPPROTO_TCP; |
||
229 | } |
||
230 | } |
||
231 | hints.ai_flags |= AI_PASSIVE; |
||
232 | hints.ai_family = family; |
||
233 | hints.ai_socktype = socktype; |
||
234 | hints.ai_protocol = protocol; |
||
235 | hints.ai_addrlen = 0; |
||
236 | hints.ai_addr = NULL; |
||
237 | hints.ai_canonname = NULL; |
||
238 | hints.ai_next = NULL; |
||
239 | |||
240 | if ((error_num = Getaddrinfo(node, service, &hints, &res)) != 0) { |
||
241 | Error7("getaddrinfo(\"%s\", \"%s\", {%d,%d,%d,%d}, {}): %s", |
||
242 | node, service, hints.ai_flags, hints.ai_family, |
||
243 | hints.ai_socktype, hints.ai_protocol, |
||
244 | (error_num == EAI_SYSTEM)? |
||
245 | strerror(errno):gai_strerror(error_num)); |
||
246 | if (res != NULL) freeaddrinfo(res); |
||
247 | if (numnode) free(numnode); |
||
248 | |||
249 | #if HAVE_RESOLV_H |
||
250 | if (res_opts0 | res_opts1) { |
||
251 | _res.options = (_res.options & (~res_opts0&~res_opts1) | |
||
252 | save_res_opts& ( res_opts0| res_opts1)); |
||
253 | } |
||
254 | #endif |
||
255 | return STAT_RETRYLATER; |
||
256 | } |
||
257 | service = NULL; /* do not resolve later again */ |
||
258 | |||
259 | record = res; |
||
260 | if (family == PF_UNSPEC && xioopts.preferred_ip == '0') { |
||
261 | /* we just take the first result */ |
||
262 | family = res[0].ai_addr->sa_family; |
||
263 | } |
||
264 | if (family == PF_UNSPEC) { |
||
265 | int trypf; |
||
266 | trypf = (xioopts.preferred_ip=='6'?PF_INET6:PF_INET); |
||
267 | /* we must look for a matching entry */ |
||
268 | while (record != NULL) { |
||
269 | if (record->ai_family == trypf) { |
||
270 | family = trypf; |
||
271 | break; /* family and record set accordingly */ |
||
272 | } |
||
273 | record = record->ai_next; |
||
274 | } |
||
275 | if (record == NULL) { |
||
276 | /* we did not find a "preferred" entry, take the first */ |
||
277 | record = res; |
||
278 | family = res[0].ai_addr->sa_family; |
||
279 | } |
||
280 | } |
||
281 | |||
282 | switch (family) { |
||
283 | #if WITH_IP4 |
||
284 | case PF_INET: |
||
285 | if (*socklen > record->ai_addrlen) { |
||
286 | *socklen = record->ai_addrlen; |
||
287 | } |
||
288 | memcpy(&sau->ip4, record->ai_addr, *socklen); |
||
289 | break; |
||
290 | #endif /* WITH_IP4 */ |
||
291 | #if WITH_IP6 |
||
292 | case PF_INET6: |
||
293 | #if _AIX |
||
294 | /* older AIX versions pass wrong length, so we correct it */ |
||
295 | record->ai_addr->sa_len = sizeof(struct sockaddr_in6); |
||
296 | #endif |
||
297 | if (*socklen > record->ai_addrlen) { |
||
298 | *socklen = record->ai_addrlen; |
||
299 | } |
||
300 | memcpy(&sau->ip6, record->ai_addr, *socklen); |
||
301 | break; |
||
302 | #endif /* WITH_IP6 */ |
||
303 | default: |
||
304 | Error1("address resolved to unknown protocol family %d", |
||
305 | record->ai_addr->sa_family); |
||
306 | break; |
||
307 | } |
||
308 | freeaddrinfo(res); |
||
309 | } else { |
||
310 | switch (family) { |
||
311 | #if WITH_IP4 |
||
312 | case PF_INET: *socklen = sizeof(sau->ip4); break; |
||
313 | #endif /* WITH_IP4 */ |
||
314 | #if WITH_IP6 |
||
315 | case PF_INET6: *socklen = sizeof(sau->ip6); break; |
||
316 | #endif /* WITH_IP6 */ |
||
317 | } |
||
318 | } |
||
319 | |||
320 | #elif HAVE_PROTOTYPE_LIB_getipnodebyname /* !HAVE_GETADDRINFO */ |
||
321 | |||
322 | if (node != NULL) { |
||
323 | /* first fallback is getipnodebyname() */ |
||
324 | if (family == PF_UNSPEC) { |
||
325 | #if WITH_IP4 && WITH_IP6 |
||
326 | family = xioopts.default_ip=='6'?PF_INET6:PF_INET; |
||
327 | #elif WITH_IP6 |
||
328 | family = PF_INET6; |
||
329 | #else |
||
330 | family = PF_INET; |
||
331 | #endif |
||
332 | } |
||
333 | host = Getipnodebyname(node, family, AI_V4MAPPED, &error_num); |
||
334 | if (host == NULL) { |
||
335 | const static char ai_host_not_found[] = "Host not found"; |
||
336 | const static char ai_no_address[] = "No address"; |
||
337 | const static char ai_no_recovery[] = "No recovery"; |
||
338 | const static char ai_try_again[] = "Try again"; |
||
339 | const char *error_msg = "Unknown error"; |
||
340 | switch (error_num) { |
||
341 | case HOST_NOT_FOUND: error_msg = ai_host_not_found; break; |
||
342 | case NO_ADDRESS: error_msg = ai_no_address; |
||
343 | case NO_RECOVERY: error_msg = ai_no_recovery; |
||
344 | case TRY_AGAIN: error_msg = ai_try_again; |
||
345 | } |
||
346 | Error2("getipnodebyname(\"%s\", ...): %s", node, error_msg); |
||
347 | } else { |
||
348 | switch (family) { |
||
349 | #if WITH_IP4 |
||
350 | case PF_INET: |
||
351 | *socklen = sizeof(sau->ip4); |
||
352 | sau->soa.sa_family = PF_INET; |
||
353 | memcpy(&sau->ip4.sin_addr, host->h_addr_list[0], 4); |
||
354 | break; |
||
355 | #endif |
||
356 | #if WITH_IP6 |
||
357 | case PF_INET6: |
||
358 | *socklen = sizeof(sau->ip6); |
||
359 | sau->soa.sa_family = PF_INET6; |
||
360 | memcpy(&sau->ip6.sin6_addr, host->h_addr_list[0], 16); |
||
361 | break; |
||
362 | #endif |
||
363 | } |
||
364 | } |
||
365 | freehostent(host); |
||
366 | } |
||
367 | |||
368 | #else /* !HAVE_PROTOTYPE_LIB_getipnodebyname */ |
||
369 | |||
370 | if (node != NULL) { |
||
371 | /* this is not a typical IP6 resolver function - but Linux |
||
372 | "man gethostbyname" says that the only supported address type with |
||
373 | this function is AF_INET _at present_, so maybe this fallback will |
||
374 | be useful somewhere sometimesin a future even for IP6 */ |
||
375 | if (family == PF_UNSPEC) { |
||
376 | #if WITH_IP4 && WITH_IP6 |
||
377 | family = xioopts.default_ip=='6'?PF_INET6:PF_INET; |
||
378 | #elif WITH_IP6 |
||
379 | family = PF_INET6; |
||
380 | #else |
||
381 | family = PF_INET; |
||
382 | #endif |
||
383 | } |
||
384 | /*!!! try gethostbyname2 for IP6 */ |
||
385 | if ((host = Gethostbyname(node)) == NULL) { |
||
386 | Error2("gethostbyname(\"%s\"): %s", node, |
||
387 | h_errno == NETDB_INTERNAL ? strerror(errno) : |
||
388 | hstrerror(h_errno)); |
||
389 | #if HAVE_RESOLV_H |
||
390 | if (res_opts0 | res_opts1) { |
||
391 | _res.options = (_res.options & (~res_opts0&~res_opts1) | |
||
392 | save_res_opts& ( res_opts0| res_opts1)); |
||
393 | } |
||
394 | #endif |
||
395 | return STAT_RETRYLATER; |
||
396 | } |
||
397 | if (host->h_addrtype != family) { |
||
398 | Error2("xioaddrinfo(): \"%s\" does not resolve to %s", |
||
399 | node, family==PF_INET?"IP4":"IP6"); |
||
400 | } else { |
||
401 | switch (family) { |
||
402 | #if WITH_IP4 |
||
403 | case PF_INET: |
||
404 | *socklen = sizeof(sau->ip4); |
||
405 | sau->soa.sa_family = PF_INET; |
||
406 | memcpy(&sau->ip4.sin_addr, host->h_addr_list[0], 4); |
||
407 | break; |
||
408 | #endif /* WITH_IP4 */ |
||
409 | #if WITH_IP6 |
||
410 | case PF_INET6: |
||
411 | *socklen = sizeof(sau->ip6); |
||
412 | sau->soa.sa_family = PF_INET6; |
||
413 | memcpy(&sau->ip6.sin6_addr, host->h_addr_list[0], 16); |
||
414 | break; |
||
415 | #endif /* WITH_IP6 */ |
||
416 | } |
||
417 | } |
||
418 | } |
||
419 | |||
420 | #endif |
||
421 | |||
422 | #if WITH_TCP || WITH_UDP |
||
423 | if (service) { |
||
424 | port = parseport(service, protocol); |
||
425 | } |
||
426 | if (port >= 0) { |
||
427 | switch (family) { |
||
428 | #if WITH_IP4 |
||
429 | case PF_INET: sau->ip4.sin_port = port; break; |
||
430 | #endif /* WITH_IP4 */ |
||
431 | #if WITH_IP6 |
||
432 | case PF_INET6: sau->ip6.sin6_port = port; break; |
||
433 | #endif /* WITH_IP6 */ |
||
434 | } |
||
435 | } |
||
436 | #endif /* WITH_TCP || WITH_UDP */ |
||
437 | |||
438 | if (numnode) free(numnode); |
||
439 | |||
440 | #if HAVE_RESOLV_H |
||
441 | if (res_opts0 | res_opts1) { |
||
442 | _res.options = (_res.options & (~res_opts0&~res_opts1) | |
||
443 | save_res_opts& ( res_opts0| res_opts1)); |
||
444 | } |
||
445 | #endif /* HAVE_RESOLV_H */ |
||
446 | return STAT_OK; |
||
447 | } |
||
448 | |||
449 | |||
450 | #if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) |
||
451 | /* converts the ancillary message in *cmsg into a form useable for further |
||
452 | processing. knows the specifics of common message types. |
||
453 | these are valid for IPv4 and IPv6 |
||
454 | returns the number of resulting syntax elements in *num |
||
455 | returns a sequence of \0 terminated type strings in *typbuff |
||
456 | returns a sequence of \0 terminated name strings in *nambuff |
||
457 | returns a sequence of \0 terminated value strings in *valbuff |
||
458 | the respective len parameters specify the available space in the buffers |
||
459 | returns STAT_OK on success |
||
460 | returns STAT_WARNING if a buffer was too short and data truncated. |
||
461 | */ |
||
462 | int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num, |
||
463 | char *typbuff, int typlen, |
||
464 | char *nambuff, int namlen, |
||
465 | char *envbuff, int envlen, |
||
466 | char *valbuff, int vallen) { |
||
467 | const char *cmsgtype, *cmsgname = NULL, *cmsgenvn = NULL, *cmsgfmt = NULL; |
||
468 | size_t msglen; |
||
469 | char scratch1[16]; /* can hold an IPv4 address in ASCII */ |
||
470 | #if WITH_IP4 && defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO |
||
471 | char scratch2[16]; |
||
472 | char scratch3[16]; |
||
473 | #endif |
||
474 | int rc = 0; |
||
475 | |||
476 | msglen = cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg); |
||
477 | envbuff[0] = '\0'; |
||
478 | switch (cmsg->cmsg_type) { |
||
479 | default: |
||
480 | *num = 1; |
||
481 | typbuff[0] = '\0'; strncat(typbuff, "IP", typlen-1); |
||
482 | snprintf(nambuff, namlen, "type_%u", cmsg->cmsg_type); |
||
483 | xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0); |
||
484 | return STAT_OK; |
||
485 | #if WITH_IP4 |
||
486 | #if defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO |
||
487 | case IP_PKTINFO: { |
||
488 | struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); |
||
489 | *num = 3; |
||
490 | typbuff[0] = '\0'; strncat(typbuff, "IP_PKTINFO", typlen-1); |
||
491 | snprintf(nambuff, namlen, "%s%c%s%c%s", "if", '\0', "locaddr", '\0', "dstaddr"); |
||
492 | snprintf(envbuff, envlen, "%s%c%s%c%s", "IP_IF", '\0', |
||
493 | "IP_LOCADDR", '\0', "IP_DSTADDR"); |
||
494 | snprintf(valbuff, vallen, "%s%c%s%c%s", |
||
495 | xiogetifname(pktinfo->ipi_ifindex, scratch1, -1), '\0', |
||
496 | #if HAVE_PKTINFO_IPI_SPEC_DST |
||
497 | inet4addr_info(ntohl(pktinfo->ipi_spec_dst.s_addr), |
||
498 | scratch2, sizeof(scratch2)), |
||
499 | #else |
||
500 | "", |
||
501 | #endif |
||
502 | '\0', |
||
503 | inet4addr_info(ntohl(pktinfo->ipi_addr.s_addr), |
||
504 | scratch3, sizeof(scratch3))); |
||
505 | } |
||
506 | return STAT_OK; |
||
507 | #endif /* defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO */ |
||
508 | #endif /* WITH_IP4 */ |
||
509 | #if defined(IP_RECVERR) && HAVE_STRUCT_SOCK_EXTENDED_ERR |
||
510 | case IP_RECVERR: { |
||
511 | struct sock_extended_err *err = |
||
512 | (struct sock_extended_err *)CMSG_DATA(cmsg); |
||
513 | *num = 6; |
||
514 | typbuff[0] = '\0'; strncat(typbuff, "IP_RECVERR", typlen-1); |
||
515 | snprintf(nambuff, namlen, "%s%c%s%c%s%c%s%c%s%c%s", |
||
516 | "errno", '\0', "origin", '\0', "type", '\0', |
||
517 | "code", '\0', "info", '\0', "data"); |
||
518 | snprintf(envbuff, envlen, "%s%c%s%c%s%c%s%c%s%c%s", |
||
519 | "IP_RECVERR_ERRNO", '\0', "IP_RECVERR_ORIGIN", '\0', |
||
520 | "IP_RECVERR_TYPE", '\0', "IP_RECVERR_CODE", '\0', |
||
521 | "IP_RECVERR_INFO", '\0', "IP_RECVERR_DATA"); |
||
522 | snprintf(valbuff, vallen, "%u%c%u%c%u%c%u%c%u%c%u", |
||
523 | err->ee_errno, '\0', err->ee_origin, '\0', err->ee_type, '\0', |
||
524 | err->ee_code, '\0', err->ee_info, '\0', err->ee_data); |
||
525 | return STAT_OK; |
||
526 | } |
||
527 | #endif /* defined(IP_RECVERR) && HAVE_STRUCT_SOCK_EXTENDED_ERR */ |
||
528 | #ifdef IP_RECVIF |
||
529 | case IP_RECVIF: { |
||
530 | /* spec in FreeBSD: /usr/include/net/if_dl.h */ |
||
531 | struct sockaddr_dl *sadl = (struct sockaddr_dl *)CMSG_DATA(cmsg); |
||
532 | *num = 1; |
||
533 | typbuff[0] = '\0'; strncat(typbuff, "IP_RECVIF", typlen-1); |
||
534 | nambuff[0] = '\0'; strncat(nambuff, "if", namlen-1); |
||
535 | envbuff[0] = '\0'; strncat(envbuff, "IP_IF", envlen-1); |
||
536 | valbuff[0] = '\0'; |
||
537 | strncat(valbuff, |
||
538 | xiosubstr(scratch1, sadl->sdl_data, 0, sadl->sdl_nlen), vallen-1); |
||
539 | return STAT_OK; |
||
540 | } |
||
541 | #endif /* defined(IP_RECVIF) */ |
||
542 | #if WITH_IP4 |
||
543 | #ifdef IP_RECVDSTADDR |
||
544 | case IP_RECVDSTADDR: |
||
545 | *num = 1; |
||
546 | typbuff[0] = '\0'; strncat(typbuff, "IP_RECVDSTADDR", typlen-1); |
||
547 | nambuff[0] = '\0'; strncat(nambuff, "dstaddr", namlen-1); |
||
548 | envbuff[0] = '\0'; strncat(envbuff, "IP_DSTADDR", envlen-1); |
||
549 | inet4addr_info(ntohl(*(uint32_t *)CMSG_DATA(cmsg)), valbuff, vallen); |
||
550 | return STAT_OK; |
||
551 | #endif |
||
552 | #endif /* WITH_IP4 */ |
||
553 | case IP_OPTIONS: |
||
554 | #ifdef IP_RECVOPTS |
||
555 | case IP_RECVOPTS: |
||
556 | #endif |
||
557 | cmsgtype = "IP_OPTIONS"; cmsgname = "options"; cmsgfmt = NULL; break; |
||
558 | case IP_TOS: |
||
559 | cmsgtype = "IP_TOS"; cmsgname = "tos"; cmsgfmt = "%u"; break; |
||
560 | case IP_TTL: /* Linux */ |
||
561 | #ifdef IP_RECVTTL |
||
562 | case IP_RECVTTL: /* FreeBSD */ |
||
563 | #endif |
||
564 | cmsgtype = "IP_TTL"; cmsgname = "ttl"; cmsgfmt = "%u"; break; |
||
565 | } |
||
566 | /* when we come here we provide a single parameter |
||
567 | with type in cmsgtype, name in cmsgname, printf format in cmsgfmt */ |
||
568 | *num = 1; |
||
569 | if (strlen(cmsgtype) >= typlen) rc = STAT_WARNING; |
||
570 | typbuff[0] = '\0'; strncat(typbuff, cmsgtype, typlen-1); |
||
571 | if (strlen(cmsgname) >= namlen) rc = STAT_WARNING; |
||
572 | nambuff[0] = '\0'; strncat(nambuff, cmsgname, namlen-1); |
||
573 | if (cmsgenvn) { |
||
574 | if (strlen(cmsgenvn) >= envlen) rc = STAT_WARNING; |
||
575 | envbuff[0] = '\0'; strncat(envbuff, cmsgenvn, envlen-1); |
||
576 | } else { |
||
577 | envbuff[0] = '\0'; |
||
578 | } |
||
579 | if (cmsgfmt != NULL) { |
||
580 | snprintf(valbuff, vallen, cmsgfmt, *(unsigned char *)CMSG_DATA(cmsg)); |
||
581 | } else { |
||
582 | xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0); |
||
583 | } |
||
584 | return rc; |
||
585 | } |
||
586 | #endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */ |
||
587 | |||
588 | #endif /* _WITH_IP4 || _WITH_IP6 */ |