2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for IP related functions */
7 #include "xiosysincludes.h"
9 #if _WITH_IP4 || _WITH_IP6
13 #include "xio-ascii.h"
14 #include "xio-socket.h"
20 #if WITH_IP4 || WITH_IP6
23 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
};
26 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
};
29 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
};
31 #ifdef IP_RECVTTL /* -Cygwin */
32 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
};
35 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
};
38 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
};
40 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
};
41 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
};
43 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
};
46 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
};
48 #ifdef IP_MTU_DISCOVER
49 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
};
52 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
};
55 const struct optdesc opt_ip_transparent
= {"ip-transparent", "transparent", OPT_IP_TRANSPARENT
, GROUP_SOCK_IP
, PH_PREBIND
, TYPE_BOOL
, OFUNC_SOCKOPT
, SOL_IP
, IP_TRANSPARENT
};
58 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
};
60 #ifdef IP_ROUTER_ALERT
61 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
};
63 /* following: Linux allows int but OpenBSD reqs char/byte */
64 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
};
65 /* following: Linux allows int but OpenBSD reqs char/byte */
66 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
};
67 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
};
69 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
};
71 #ifdef IP_ADD_MEMBERSHIP
72 const struct optdesc opt_ip_add_membership
= { "ip-add-membership", "membership",OPT_IP_ADD_MEMBERSHIP
, GROUP_SOCK_IP
, PH_PASTSOCKET
, TYPE_IP_MREQN
, OFUNC_SPEC
, SOL_IP
, IP_ADD_MEMBERSHIP
};
74 #if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP)
75 const struct optdesc opt_ip_add_source_membership
= { "ip-add-source-membership", "source-membership",OPT_IP_ADD_SOURCE_MEMBERSHIP
, GROUP_SOCK_IP
, PH_PASTSOCKET
, TYPE_IP_MREQ_SOURCE
, OFUNC_SOCKOPT
, SOL_IP
, IP_ADD_SOURCE_MEMBERSHIP
};
78 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
};
81 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
};
85 const struct optdesc opt_ai_addrconfig
= { "ai-addrconfig", "addrconfig", OPT_AI_ADDRCONFIG
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.socket
.ip
.ai_flags
), XIO_SIZEOF(para
.socket
.ip
.ai_flags
), AI_ADDRCONFIG
};
88 const struct optdesc opt_ai_v4mapped
= { "ai-v4mapped", "v4mapped", OPT_AI_V4MAPPED
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.socket
.ip
.ai_flags
), XIO_SIZEOF(para
.socket
.ip
.ai_flags
), AI_V4MAPPED
};
91 const struct optdesc opt_ai_passive
= { "ai-passive", "passive", OPT_AI_PASSIVE
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.socket
.ip
.ai_flags
), XIO_SIZEOF(para
.socket
.ip
.ai_flags
), AI_PASSIVE
};
95 #if WITH_RES_DEPRECATED
96 # define WITH_RES_AAONLY 1
97 # define WITH_RES_PRIMARY 1
98 #endif /* WITH_RES_DEPRECATED */
100 const struct optdesc opt_res_debug
= { "res-debug", NULL
, OPT_RES_DEBUG
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.socket
.ip
.res
.opts
), XIO_SIZEOF(para
.socket
.ip
.res
.opts
), RES_DEBUG
};
102 const struct optdesc opt_res_aaonly
= { "res-aaonly", "aaonly", OPT_RES_AAONLY
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.socket
.ip
.res
.opts
), XIO_SIZEOF(para
.socket
.ip
.res
.opts
), RES_AAONLY
};
104 const struct optdesc opt_res_usevc
= { "res-usevc", "usevc", OPT_RES_USEVC
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.socket
.ip
.res
.opts
), XIO_SIZEOF(para
.socket
.ip
.res
.opts
), RES_USEVC
};
106 const struct optdesc opt_res_primary
= { "res-primary", "primary", OPT_RES_PRIMARY
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.socket
.ip
.res
.opts
), XIO_SIZEOF(para
.socket
.ip
.res
.opts
), RES_PRIMARY
};
108 const struct optdesc opt_res_igntc
= { "res-igntc", "igntc", OPT_RES_IGNTC
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.socket
.ip
.res
.opts
), XIO_SIZEOF(para
.socket
.ip
.res
.opts
), RES_IGNTC
};
109 const struct optdesc opt_res_recurse
= { "res-recurse", "recurse", OPT_RES_RECURSE
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.socket
.ip
.res
.opts
), XIO_SIZEOF(para
.socket
.ip
.res
.opts
), RES_RECURSE
};
110 const struct optdesc opt_res_defnames
= { "res-defnames", "defnames", OPT_RES_DEFNAMES
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.socket
.ip
.res
.opts
), XIO_SIZEOF(para
.socket
.ip
.res
.opts
), RES_DEFNAMES
};
111 const struct optdesc opt_res_stayopen
= { "res-stayopen", "stayopen", OPT_RES_STAYOPEN
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.socket
.ip
.res
.opts
), XIO_SIZEOF(para
.socket
.ip
.res
.opts
), RES_STAYOPEN
};
112 const struct optdesc opt_res_dnsrch
= { "res-dnsrch", "dnsrch", OPT_RES_DNSRCH
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.socket
.ip
.res
.opts
), XIO_SIZEOF(para
.socket
.ip
.res
.opts
), RES_DNSRCH
};
114 const struct optdesc opt_res_retrans
= { "res-retrans", "retrans", OPT_RES_RETRANS
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_INT
, OFUNC_OFFSET
, XIO_OFFSETOF(para
.socket
.ip
.res
.retrans
), XIO_SIZEOF(para
.socket
.ip
.res
.retrans
), RES_MAXRETRANS
};
117 const struct optdesc opt_res_retry
= { "res-retry", NULL
, OPT_RES_RETRY
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_INT
, OFUNC_OFFSET
, XIO_OFFSETOF(para
.socket
.ip
.res
.retry
), XIO_SIZEOF(para
.socket
.ip
.res
.retry
), RES_MAXRETRY
};
119 #if HAVE_RES_NSADDR_LIST
120 const struct optdesc opt_res_nsaddr
= { "res-nsaddr", "dns", OPT_RES_NSADDR
, GROUP_SOCK_IP
, PH_OFFSET
, TYPE_IP4SOCK
, OFUNC_OFFSET
, XIO_OFFSETOF(para
.socket
.ip
.res
.nsaddr
), XIO_SIZEOF(para
.socket
.ip
.res
.retry
), RES_MAXRETRY
};
122 #endif /* HAVE_RESOLV_H */
123 #endif /* WITH_RESOLVE */
124 #endif /* WITH_IP4 || WITH_IP6 */
131 if (*pf
== PF_UNSPEC
) {
133 case '0': *pf
= PF_UNSPEC
; break;
135 case '4': *pf
= PF_INET
; break;
138 case '6': *pf
= PF_INET6
; break;
152 Debug1("res_init() -> %d", result
);
156 #endif /* HAVE_RESOLV_H */
159 /* the ultimate(?) socat resolver function
160 node: the address to be resolved; supported forms:
161 1.2.3.4 (IPv4 address)
163 hostname (hostname resolving to IPv4 or IPv6 address)
164 hostname.domain (fq hostname resolving to IPv4 or IPv6 address)
165 service: the port specification; may be numeric or symbolic
166 family: PF_INET, PF_INET6, or PF_UNSPEC permitting both
167 socktype: SOCK_STREAM, SOCK_DGRAM, ...
168 protocol: IPPROTO_UDP, IPPROTO_TCP
169 sau: an uninitialized storage for the resulting socket address
170 returns: STAT_OK, STAT_RETRYLATER, STAT_NORETRY, prints message
172 int xiogetaddrinfo(const char *node
, const char *service
,
173 int family
, int socktype
, int protocol
,
174 struct addrinfo
**res
, const int ai_flags
[2]) {
175 char *numnode
= NULL
;
178 struct addrinfo hints
= {0};
179 #else /* HAVE_PROTOTYPE_LIB_getipnodebyname || nothing */
180 struct hostent
*host
;
184 if (service
&& service
[0]=='\0') {
185 Error("empty port/service");
190 if (family
== AF_VSOCK
) {
191 error_num
= sockaddr_vm_parse(&sau
->vm
, node
, service
);
197 #endif /* WITH_VSOCK */
200 /* the resolver functions might handle numeric forms of node names by
201 reverse lookup, that's not what we want.
202 So we detect these and handle them specially */
203 if (0) { /* for canonical reasons */
206 } else if (node
&& node
[0] == '[' && node
[(nodelen
=strlen(node
))-1]==']') {
207 if ((numnode
= Malloc(nodelen
-1)) == NULL
)
210 strncpy(numnode
, node
+1, nodelen
-2); /* ok */
211 numnode
[nodelen
-2] = '\0';
214 hints
.ai_flags
|= AI_NUMERICHOST
;
215 #endif /* HAVE_GETADDRINFO */
216 if (family
== PF_UNSPEC
) family
= PF_INET6
;
217 #endif /* WITH_IP6 */
220 hints
.ai_flags
|= AI_ADDRCONFIG
;
222 if (node
!= NULL
|| service
!= NULL
) {
223 struct addrinfo
*record
;
225 if (ai_flags
!= NULL
) {
226 hints
.ai_flags
|= ai_flags
[0];
227 hints
.ai_flags
&= ~ai_flags
[1];
229 hints
.ai_family
= family
;
230 hints
.ai_socktype
= socktype
;
231 hints
.ai_protocol
= protocol
;
232 hints
.ai_addrlen
= 0;
233 hints
.ai_addr
= NULL
;
234 hints
.ai_canonname
= NULL
;
235 hints
.ai_next
= NULL
;
238 error_num
= Getaddrinfo(node
, service
, &hints
, res
);
239 if (error_num
== 0) break;
240 if (error_num
== EAI_SOCKTYPE
&& socktype
!= 0) {
241 /* there are systems where kernel goes SCTP but not getaddrinfo() */
242 hints
.ai_socktype
= 0;
245 if (error_num
== EAI_SERVICE
&& protocol
!= 0) {
246 if (hints
.ai_protocol
== 0) {
247 Error7("getaddrinfo(\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %s",
248 node
?node
:"NULL", service
?service
:"NULL",
249 hints
.ai_flags
, hints
.ai_family
,
250 hints
.ai_socktype
, hints
.ai_protocol
,
251 gai_strerror(error_num
));
258 /* Probably unsupported protocol (e.g. UDP-Lite), fallback to 0 */
259 hints
.ai_protocol
= 0;
262 if ((error_num
= Getaddrinfo(node
, service
, &hints
, res
)) != 0) {
263 Error7("getaddrinfo(\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %s",
264 node
?node
:"NULL", service
?service
:"NULL",
265 hints
.ai_flags
, hints
.ai_family
,
266 hints
.ai_socktype
, hints
.ai_protocol
,
267 (error_num
== EAI_SYSTEM
)?
268 strerror(errno
):gai_strerror(error_num
));
274 return STAT_RETRYLATER
;
277 service
= NULL
; /* do not resolve later again */
279 #if WITH_MSGLEVEL <= E_DEBUG
283 sockaddr_info(record
->ai_addr
, record
->ai_addrlen
, buff
, sizeof(buff
));
284 Debug5("getaddrinfo() -> flags=0x%02x family=%d socktype=%d protocol=%d addr=%s", record
->ai_flags
, record
->ai_family
, record
->ai_socktype
, record
->ai_protocol
, buff
);
285 record
= record
->ai_next
;
287 #endif /* WITH_MSGLEVEL <= E_DEBUG */
290 #elif HAVE_PROTOTYPE_LIB_getipnodebyname /* !HAVE_GETADDRINFO */
293 /* first fallback is getipnodebyname() */
294 if (family
== PF_UNSPEC
) {
295 #if WITH_IP4 && WITH_IP6
296 switch (xioparms
.default_ip
) {
297 case '4': pf
= PF_INET
; break;
298 case '6': pf
= PF_INET6
; break;
299 default: break; /* includes \0 */
307 host
= Getipnodebyname(node
, family
, AI_V4MAPPED
, &error_num
);
309 const static char ai_host_not_found
[] = "Host not found";
310 const static char ai_no_address
[] = "No address";
311 const static char ai_no_recovery
[] = "No recovery";
312 const static char ai_try_again
[] = "Try again";
313 const char *error_msg
= "Unknown error";
315 case HOST_NOT_FOUND
: error_msg
= ai_host_not_found
; break;
316 case NO_ADDRESS
: error_msg
= ai_no_address
;
317 case NO_RECOVERY
: error_msg
= ai_no_recovery
;
318 case TRY_AGAIN
: error_msg
= ai_try_again
;
320 Error2("getipnodebyname(\"%s\", ...): %s", node
, error_msg
);
325 *socklen
= sizeof(sau
->ip4
);
326 sau
->soa
.sa_family
= PF_INET
;
327 memcpy(&sau
->ip4
.sin_addr
, host
->h_addr_list
[0], 4);
332 *socklen
= sizeof(sau
->ip6
);
333 sau
->soa
.sa_family
= PF_INET6
;
334 memcpy(&sau
->ip6
.sin6_addr
, host
->h_addr_list
[0], 16);
342 #elsif 0 /* !HAVE_PROTOTYPE_LIB_getipnodebyname */
345 /* this is not a typical IP6 resolver function - but Linux
346 "man gethostbyname" says that the only supported address type with
347 this function is AF_INET _at present_, so maybe this fallback will
348 be useful somewhere sometimes in a future even for IP6 */
349 if (family
== PF_UNSPEC
) {
350 #if WITH_IP4 && WITH_IP6
351 switch (xioparms
.default_ip
) {
352 case '4': pf
= PF_INET
; break;
353 case '6': pf
= PF_INET6
; break;
354 default: break; /* includes \0 */
362 /*!!! try gethostbyname2 for IP6 */
363 if ((host
= Gethostbyname(node
)) == NULL
) {
364 Error2("gethostbyname(\"%s\"): %s", node
,
365 h_errno
== NETDB_INTERNAL
? strerror(errno
) :
367 return STAT_RETRYLATER
;
369 if (host
->h_addrtype
!= family
) {
370 Error2("xiogetaddrinfo(): \"%s\" does not resolve to %s",
371 node
, family
==PF_INET
?"IP4":"IP6");
376 *socklen
= sizeof(sau
->ip4
);
377 sau
->soa
.sa_family
= PF_INET
;
378 memcpy(&sau
->ip4
.sin_addr
, host
->h_addr_list
[0], 4);
380 #endif /* WITH_IP4 */
383 *socklen
= sizeof(sau
->ip6
);
384 sau
->soa
.sa_family
= PF_INET6
;
385 memcpy(&sau
->ip6
.sin6_addr
, host
->h_addr_list
[0], 16);
387 #endif /* WITH_IP6 */
394 if (numnode
) free(numnode
);
399 void xiofreeaddrinfo(struct addrinfo
*res
) {
407 /* A simple resolver interface that just returns one address,
408 the first found by calling xiogetaddrinfo().
409 family may be AF_INET, AF_INET6, or AF_UNSPEC;
410 Returns -1 when an error occurred or when no result found.
412 int xioresolve(const char *node
, const char *service
,
413 int family
, int socktype
, int protocol
,
414 union sockaddr_union
*addr
, socklen_t
*addrlen
,
415 const int ai_flags
[2])
417 struct addrinfo
*res
= NULL
;
418 struct addrinfo
*aip
;
421 rc
= xiogetaddrinfo(node
, service
, family
, socktype
, protocol
,
424 xiofreeaddrinfo(res
);
428 Warn1("xioresolve(node=\"%s\", ...): No result", node
);
429 xiofreeaddrinfo(res
);
432 if (res
->ai_addrlen
> *addrlen
) {
433 Warn3("xioresolve(node=\"%s\", addrlen="F_socklen
", ...): "F_socklen
" bytes required", node
, *addrlen
, res
->ai_addrlen
);
434 xiofreeaddrinfo(res
);
437 if (res
->ai_next
!= NULL
) {
438 Info4("xioresolve(node=\"%s\", service=%s%s%s, ...): More than one address found", node
?node
:"NULL", service
?"\"":"", service
?service
:"NULL", service
?"\"":"");
442 if (ai_flags
!= NULL
&& ai_flags
[0] & AI_PASSIVE
&& family
== PF_UNSPEC
) {
443 /* We select the first IPv6 address, if available,
444 because this might accept IPv4 connections too */
445 while (aip
!= NULL
) {
446 if (aip
->ai_family
== PF_INET6
)
454 memcpy(addr
, aip
->ai_addr
, aip
->ai_addrlen
);
455 *addrlen
= aip
->ai_addrlen
;
456 xiofreeaddrinfo(res
);
460 #if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
461 /* Converts the ancillary message in *cmsg into a form useable for further
462 processing. knows the specifics of common message types.
463 These are valid for IPv4 and IPv6
464 Returns the number of resulting syntax elements in *num
465 Returns a sequence of \0 terminated type strings in *typbuff
466 Returns a sequence of \0 terminated name strings in *nambuff
467 Returns a sequence of \0 terminated value strings in *valbuff
468 The respective len parameters specify the available space in the buffers
469 Returns STAT_OK on success
470 Returns STAT_WARNING if a buffer was too short and data truncated.
472 int xiolog_ancillary_ip(
474 struct cmsghdr
*cmsg
,
476 char *typbuff
, int typlen
,
477 char *nambuff
, int namlen
,
478 char *envbuff
, int envlen
,
479 char *valbuff
, int vallen
)
482 const char *cmsgtype
, *cmsgname
= NULL
, *cmsgenvn
= NULL
;
484 char scratch1
[16]; /* can hold an IPv4 address in ASCII */
485 #if WITH_IP4 && defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO
491 msglen
= cmsg
->cmsg_len
-((char *)CMSG_DATA(cmsg
)-(char *)cmsg
);
493 switch (cmsg
->cmsg_type
) {
496 typbuff
[0] = '\0'; strncat(typbuff
, "IP", typlen
-1);
497 snprintf(nambuff
, namlen
, "type_%u", cmsg
->cmsg_type
);
498 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
501 #if defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO
503 struct in_pktinfo
*pktinfo
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
505 typbuff
[0] = '\0'; strncat(typbuff
, "IP_PKTINFO", typlen
-1);
506 snprintf(nambuff
, namlen
, "%s%c%s%c%s", "if", '\0', "locaddr", '\0', "dstaddr");
507 snprintf(envbuff
, envlen
, "%s%c%s%c%s", "IP_IF", '\0',
508 "IP_LOCADDR", '\0', "IP_DSTADDR");
509 snprintf(valbuff
, vallen
, "%s%c%s%c%s",
510 xiogetifname(pktinfo
->ipi_ifindex
, scratch1
, -1), '\0',
511 #if HAVE_PKTINFO_IPI_SPEC_DST
512 inet4addr_info(ntohl(pktinfo
->ipi_spec_dst
.s_addr
),
513 scratch2
, sizeof(scratch2
)),
518 inet4addr_info(ntohl(pktinfo
->ipi_addr
.s_addr
),
519 scratch3
, sizeof(scratch3
)));
520 Notice3("Ancillary message: interface \"%s\", locaddr=%s, dstaddr=%s",
521 xiogetifname(pktinfo
->ipi_ifindex
, scratch1
, -1),
522 #if HAVE_PKTINFO_IPI_SPEC_DST
523 inet4addr_info(ntohl(pktinfo
->ipi_spec_dst
.s_addr
),
524 scratch2
, sizeof(scratch2
)),
528 inet4addr_info(ntohl(pktinfo
->ipi_addr
.s_addr
),
529 scratch3
, sizeof(scratch3
)));
532 #endif /* defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO */
533 #endif /* WITH_IP4 */
534 #if defined(IP_RECVERR) && HAVE_STRUCT_SOCK_EXTENDED_ERR
536 struct xio_extended_err
{
537 struct sock_extended_err see
;
543 struct xio_extended_err
*err
=
544 (struct xio_extended_err
*)CMSG_DATA(cmsg
);
546 typbuff
[0] = '\0'; strncat(typbuff
, "IP_RECVERR", typlen
-1);
547 snprintf(nambuff
, namlen
, "%s%c%s%c%s%c%s%c%s%c%s",
548 "errno", '\0', "origin", '\0', "type", '\0',
549 "code", '\0', "info", '\0', "data");
550 snprintf(envbuff
, envlen
, "%s%c%s%c%s%c%s%c%s%c%s",
551 "IP_RECVERR_ERRNO", '\0', "IP_RECVERR_ORIGIN", '\0',
552 "IP_RECVERR_TYPE", '\0', "IP_RECVERR_CODE", '\0',
553 "IP_RECVERR_INFO", '\0', "IP_RECVERR_DATA");
554 snprintf(valbuff
, vallen
, "%u%c%u%c%u%c%u%c%u%c%u",
555 err
->see
.ee_errno
, '\0', err
->see
.ee_origin
, '\0', err
->see
.ee_type
, '\0',
556 err
->see
.ee_code
, '\0', err
->see
.ee_info
, '\0', err
->see
.ee_data
);
558 switch (err
->see
.ee_origin
) {
561 case SO_EE_ORIGIN_ICMP
:
563 inet4addr_info(ntohl(err
->data1
), addrbuff
, sizeof(addrbuff
));
564 Notice6("received ICMP from %s, type %d, code %d, info %d, data %d, resulting in errno %d",
565 addrbuff
, err
->see
.ee_type
, err
->see
.ee_code
, err
->see
.ee_info
, err
->see
.ee_data
, err
->see
.ee_errno
);
568 #endif /* WITH_IP4 */
570 case SO_EE_ORIGIN_ICMP6
:
572 Notice5("received ICMP type %d, code %d, info %d, data %d, resulting in errno %d",
573 err
->see
.ee_type
, err
->see
.ee_code
, err
->see
.ee_info
, err
->see
.ee_data
, err
->see
.ee_errno
);
576 #endif /* WITH_IP6 */
578 Notice6("received error message origin %d, type %d, code %d, info %d, data %d, generating errno %d",
579 err
->see
.ee_origin
, err
->see
.ee_type
, err
->see
.ee_code
, err
->see
.ee_info
, err
->see
.ee_data
, err
->see
.ee_errno
);
584 #endif /* defined(IP_RECVERR) && HAVE_STRUCT_SOCK_EXTENDED_ERR */
587 /* spec in FreeBSD: /usr/include/net/if_dl.h */
588 struct sockaddr_dl
*sadl
= (struct sockaddr_dl
*)CMSG_DATA(cmsg
);
590 typbuff
[0] = '\0'; strncat(typbuff
, "IP_RECVIF", typlen
-1);
591 nambuff
[0] = '\0'; strncat(nambuff
, "if", namlen
-1);
592 envbuff
[0] = '\0'; strncat(envbuff
, "IP_IF", envlen
-1);
595 xiosubstr(scratch1
, sadl
->sdl_data
, 0, sadl
->sdl_nlen
), vallen
-1);
596 Notice1("IP_RECVIF: %s", valbuff
);
599 #endif /* defined(IP_RECVIF) */
601 #ifdef IP_RECVDSTADDR
604 typbuff
[0] = '\0'; strncat(typbuff
, "IP_RECVDSTADDR", typlen
-1);
605 nambuff
[0] = '\0'; strncat(nambuff
, "dstaddr", namlen
-1);
606 envbuff
[0] = '\0'; strncat(envbuff
, "IP_DSTADDR", envlen
-1);
607 inet4addr_info(ntohl(*(uint32_t *)CMSG_DATA(cmsg
)), valbuff
, vallen
);
608 Notice1("IP_RECVDSTADDR: %s", valbuff
);
611 #endif /* WITH_IP4 */
616 cmsgtype
= "IP_OPTIONS"; cmsgname
= "options"; cmsgctr
= -1;
619 #if XIO_ANCILLARY_TYPE_SOLARIS
624 cmsgtype
= "IP_TOS"; cmsgname
= "tos"; cmsgctr
= msglen
;
626 case IP_TTL
: /* Linux */
628 case IP_RECVTTL
: /* FreeBSD */
630 cmsgtype
= "IP_TTL"; cmsgname
= "ttl"; cmsgctr
= msglen
; break;
632 /* when we come here we provide a single parameter
633 with name in cmsgname, value length in msglen */
635 if (strlen(cmsgtype
) >= typlen
) rc
= STAT_WARNING
;
636 typbuff
[0] = '\0'; strncat(typbuff
, cmsgtype
, typlen
-1);
637 if (strlen(cmsgname
) >= namlen
) rc
= STAT_WARNING
;
638 nambuff
[0] = '\0'; strncat(nambuff
, cmsgname
, namlen
-1);
640 if (strlen(cmsgenvn
) >= envlen
) rc
= STAT_WARNING
;
641 envbuff
[0] = '\0'; strncat(envbuff
, cmsgenvn
, envlen
-1);
647 snprintf(valbuff
, vallen
, "%u", *(unsigned char *)CMSG_DATA(cmsg
));
648 Notice2("Ancillary message: %s=%u", cmsgname
, *(unsigned char *)CMSG_DATA(cmsg
));
651 snprintf(valbuff
, vallen
, "%u", (*(unsigned int *)CMSG_DATA(cmsg
)));
652 Notice2("Ancillary message: %s=%u", cmsgname
, *(unsigned int *)CMSG_DATA(cmsg
));
655 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0); break;
660 #endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */
663 #if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
664 int xiotype_ip_add_membership(
666 const struct optname
*ent
,
669 /* we do not resolve the addresses here because we do not yet know
670 if we are coping with a IPv4 or IPv6 socat address */
671 const char *ends
[] = { ":", NULL
};
672 const char *nests
[] = { "[","]", NULL
};
673 char buff
[512], *buffp
=buff
; size_t bufspc
= sizeof(buff
)-1;
676 /* parse first IP address, expect ':' */
679 nestlex((const char **)&tokp
, &buffp
, &bufspc
,
680 ends
, NULL
, NULL
, nests
,
683 Error1("option too long: \"%s\"", tokp
);
685 } else if (parsres
> 0) {
686 Error1("syntax error in \"%s\"", tokp
);
690 Error1("syntax in option %s: missing ':'", tokp
);
693 if ((opt
->value
.u_string
/*multiaddr*/ = strdup(buff
)) == NULL
) {
694 Error1("strdup(\"%s\"): out of memory", buff
);
699 /* parse second IP address, expect ':' or '\0'' */
703 nestlex((const char **)&tokp
, &buffp
, &bufspc
,
704 ends
, NULL
, NULL
, nests
,
707 Error1("option too long: \"%s\"", tokp
);
709 } else if (parsres
> 0) {
710 Error1("syntax error in \"%s\"", tokp
);
714 if ((opt
->value2
.u_string
/*param2*/ = strdup(buff
)) == NULL
) {
715 Error1("strdup(\"%s\"): out of memory", buff
);
716 free(opt
->value
.u_string
);
721 #if HAVE_STRUCT_IP_MREQN
722 if (*tokp
++ == ':') {
723 strncpy(opt
->value3
.u_string
/*ifindex*/, tokp
, IF_NAMESIZE
); /* ok */
724 Info4("setting option \"%s\" to {\"%s\",\"%s\",\"%s\"}",
726 opt
->value
.u_string
/*multiaddr*/,
727 opt
->value2
.u_string
/*param2*/,
728 opt
->value3
.u_string
/*ifindex*/);
730 /*0 opt->value3.u_string = NULL; / * is NULL from init */
731 Info3("setting option \"%s\" to {\"%s\",\"%s\"}",
733 opt
->value
.u_string
/*multiaddr*/,
734 opt
->value2
.u_string
/*param2*/);
736 #else /* !HAVE_STRUCT_IP_MREQN */
737 Info3("setting option \"%s\" to {\"%s\",\"%s\"}",
739 opt
->value
.u_string
/*multiaddr*/,
740 opt
->value2
.u_string
/*param2*/);
741 #endif /* !HAVE_STRUCT_IP_MREQN */
744 #endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */
746 #if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
747 int xioapply_ip_add_membership(
752 #if HAVE_STRUCT_IP_MREQN
753 struct ip_mreqn mreqn
;
756 } ip4_mreqn
= {{{0}}};
757 /* IPv6 not supported - seems to have different handling */
763 union sockaddr_union sockaddr1
;
764 socklen_t socklen1
= sizeof(sockaddr1
.ip4
);
765 union sockaddr_union sockaddr2
;
766 socklen_t socklen2
= sizeof(sockaddr2
.ip4
);
768 /* First parameter is always multicast address */
770 xioresolve(opt
->value
.u_string
/*multiaddr*/, NULL
,
771 sfd
->para
.socket
.la
.soa
.sa_family
,
772 SOCK_DGRAM
, IPPROTO_IP
, &sockaddr1
, &socklen1
,
773 sfd
->para
.socket
.ip
.ai_flags
);
774 ip4_mreqn
.mreq
.imr_multiaddr
= sockaddr1
.ip4
.sin_addr
;
776 ; /* for canonical reasons */
777 #if HAVE_STRUCT_IP_MREQN
778 } else if (opt
->value3
.u_string
/*ifindex*/ != NULL
) {
779 /* three parameters */
780 /* second parameter is interface address */
781 xioresolve(opt
->value2
.u_string
/*param2*/, NULL
,
782 sfd
->para
.socket
.la
.soa
.sa_family
,
783 SOCK_DGRAM
, IPPROTO_IP
, &sockaddr2
, &socklen2
,
784 sfd
->para
.socket
.ip
.ai_flags
);
785 ip4_mreqn
.mreq
.imr_interface
= sockaddr2
.ip4
.sin_addr
;
786 /* third parameter is interface */
787 if (ifindex(opt
->value3
.u_string
/*ifindex*/,
788 (unsigned int *)&ip4_mreqn
.mreqn
.imr_ifindex
, -1)
790 Error1("cannot resolve interface \"%s\"",
791 opt
->value3
.u_string
/*ifindex*/);
793 #endif /* HAVE_STRUCT_IP_MREQN */
797 ; /* for canonical reasons */
798 #if HAVE_STRUCT_IP_MREQN
799 /* there is a form with two parameters that uses mreqn */
800 } else if (ifindex(opt
->value2
.u_string
/*param2*/,
801 (unsigned int *)&ip4_mreqn
.mreqn
.imr_ifindex
,
804 /* yes, second param converts to interface */
805 ip4_mreqn
.mreq
.imr_interface
.s_addr
= htonl(0);
806 #endif /* HAVE_STRUCT_IP_MREQN */
809 xioresolve(opt
->value2
.u_string
/*param2*/, NULL
,
810 sfd
->para
.socket
.la
.soa
.sa_family
,
811 SOCK_DGRAM
, IPPROTO_IP
,
812 &sockaddr2
, &socklen2
,
813 sfd
->para
.socket
.ip
.ai_flags
);
814 ip4_mreqn
.mreq
.imr_interface
= sockaddr2
.ip4
.sin_addr
;
820 ; /* for canonical reasons */
821 } else if (sfd
->para
.socket
.la
.soa
.sa_family
== PF_INET
) {
822 } else if (sfd
->para
.socket
.la
.soa
.sa_family
== PF_INET6
) {
823 ip6_mreqn
.mreq
.imr_multiaddr
= sockaddr1
.ip6
.sin6_addr
;
824 ip6_mreqn
.mreq
.imr_interface
= sockaddr2
.ip6
.sin6_addr
;
828 #if HAVE_STRUCT_IP_MREQN
829 if (Setsockopt(sfd
->fd
, opt
->desc
->major
, opt
->desc
->minor
,
830 &ip4_mreqn
.mreqn
, sizeof(ip4_mreqn
.mreqn
)) < 0) {
831 Error8("setsockopt(%d, %d, %d, {0x%08x,0x%08x,%d}, "F_Zu
"): %s",
832 sfd
->fd
, opt
->desc
->major
, opt
->desc
->minor
,
833 ip4_mreqn
.mreqn
.imr_multiaddr
.s_addr
,
834 ip4_mreqn
.mreqn
.imr_address
.s_addr
,
835 ip4_mreqn
.mreqn
.imr_ifindex
,
836 sizeof(ip4_mreqn
.mreqn
),
838 opt
->desc
= ODESC_ERROR
;
842 if (Setsockopt(sfd
->fd
, opt
->desc
->major
, opt
->desc
->minor
,
843 &ip4_mreqn
.mreq
, sizeof(ip4_mreqn
.mreq
)) < 0) {
844 Error7("setsockopt(%d, %d, %d, {0x%08x,0x%08x}, "F_Zu
"): %s",
845 sfd
->fd
, opt
->desc
->major
, opt
->desc
->minor
,
846 ip4_mreqn
.mreq
.imr_multiaddr
,
847 ip4_mreqn
.mreq
.imr_interface
,
848 sizeof(ip4_mreqn
.mreq
),
850 opt
->desc
= ODESC_ERROR
;
856 #endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */
859 #if HAVE_STRUCT_IP_MREQ_SOURCE
860 int xiotype_ip_add_source_membership(char *token
, const struct optname
*ent
, struct opt
*opt
) {
861 /* we do not resolve the addresses here because we do not yet know
862 if we are coping with an IPv4 or IPv6 socat address */
863 const char *ends
[] = { ":", NULL
};
864 const char *nests
[] = { "[","]", NULL
};
865 char buff
[512], *buffp
=buff
; size_t bufspc
= sizeof(buff
)-1;
869 /* parse first IP address, expect ':' */
871 nestlex((const char **)&tokp
, &buffp
, &bufspc
,
872 ends
, NULL
, NULL
, nests
,
875 Error1("option too long: \"%s\"", token
);
877 } else if (parsres
> 0) {
878 Error1("syntax error in \"%s\"", token
);
882 Error1("syntax in option %s: missing ':'", token
);
885 if ((opt
->value
.u_string
/*mcaddr*/ = strdup(buff
)) == NULL
) {
886 Error1("strdup(\"%s\"): out of memory", buff
);
891 /* parse second IP address, expect ':' or '\0'' */
895 nestlex((const char **)&tokp
, &buffp
, &bufspc
,
896 ends
, NULL
, NULL
, nests
,
899 Error1("option too long: \"%s\"", token
);
901 } else if (parsres
> 0) {
902 Error1("syntax error in \"%s\"", token
);
906 Error1("syntax in option %s: missing ':'", token
);
909 if ((opt
->value2
.u_string
/*ifaddr*/ = strdup(buff
)) == NULL
) {
910 Error1("strdup(\"%s\"): out of memory", buff
);
911 free(opt
->value
.u_string
);
916 /* parse third IP address, expect ':' or '\0'' */
920 nestlex((const char **)&tokp
, &buffp
, &bufspc
,
921 ends
, NULL
, NULL
, nests
,
924 Error1("option too long: \"%s\"", token
);
926 } else if (parsres
> 0) {
927 Error1("syntax error in \"%s\"", token
);
931 Error1("syntax in option %s: trailing cruft", token
);
934 if ((opt
->value3
.u_string
/*srcaddr*/ = strdup(buff
)) == NULL
) {
935 Error1("strdup(\"%s\"): out of memory", buff
);
936 free(opt
->value
.u_string
);
937 free(opt
->value2
.u_string
);
941 Info4("setting option \"%s\" to {0x%08x,0x%08x,0x%08x}",
943 ntohl(*(unsigned int *)opt
->value
.u_string
/*mcaddr*/),
944 ntohl(*(unsigned int *)opt
->value2
.u_string
/*ifaddr*/),
945 ntohl(*(unsigned int *)opt
->value3
.u_string
/*srcaddr*/));
949 int xioapply_ip_add_source_membership(struct single
*sfd
, struct opt
*opt
) {
950 struct ip_mreq_source ip4_mreq_src
= {{0}};
951 /* IPv6 not supported - seems to have different handling */
952 union sockaddr_union sockaddr1
;
953 socklen_t socklen1
= sizeof(sockaddr1
.ip4
);
954 union sockaddr_union sockaddr2
;
955 socklen_t socklen2
= sizeof(sockaddr2
.ip4
);
956 union sockaddr_union sockaddr3
;
957 socklen_t socklen3
= sizeof(sockaddr3
.ip4
);
960 /* first parameter is always multicast address */
961 rc
= xioresolve(opt
->value
.u_string
/*mcaddr*/, NULL
,
962 sfd
->para
.socket
.la
.soa
.sa_family
,
963 SOCK_DGRAM
, IPPROTO_IP
,
964 &sockaddr1
, &socklen1
, sfd
->para
.socket
.ip
.ai_flags
);
968 ip4_mreq_src
.imr_multiaddr
= sockaddr1
.ip4
.sin_addr
;
969 /* second parameter is interface address */
970 rc
= xioresolve(opt
->value
.u_string
/*ifaddr*/, NULL
,
971 sfd
->para
.socket
.la
.soa
.sa_family
,
972 SOCK_DGRAM
, IPPROTO_IP
,
973 &sockaddr2
, &socklen2
, sfd
->para
.socket
.ip
.ai_flags
);
977 ip4_mreq_src
.imr_interface
= sockaddr2
.ip4
.sin_addr
;
978 /* third parameter is source address */
979 rc
= xioresolve(opt
->value
.u_string
/*srcaddr*/, NULL
,
980 sfd
->para
.socket
.la
.soa
.sa_family
,
981 SOCK_DGRAM
, IPPROTO_IP
,
982 &sockaddr3
, &socklen3
, sfd
->para
.socket
.ip
.ai_flags
);
986 ip4_mreq_src
.imr_sourceaddr
= sockaddr3
.ip4
.sin_addr
;
987 if (Setsockopt(sfd
->fd
, opt
->desc
->major
, opt
->desc
->minor
,
988 &ip4_mreq_src
, sizeof(ip4_mreq_src
)) < 0) {
989 Error8("setsockopt(%d, %d, %d, {0x%08x,0x%08x,0x%08x}, "F_Zu
"): %s",
990 sfd
->fd
, opt
->desc
->major
, opt
->desc
->minor
,
991 htonl((uint32_t)ip4_mreq_src
.imr_multiaddr
.s_addr
),
992 ip4_mreq_src
.imr_interface
.s_addr
,
993 ip4_mreq_src
.imr_sourceaddr
.s_addr
,
994 sizeof(struct ip_mreq_source
),
996 opt
->desc
= ODESC_ERROR
;
1002 #endif /* HAVE_STRUCT_IP_MREQ_SOURCE */
1008 /* When there are options for resolver then this function saves the current
1009 resolver settings to save_res and applies the options to resolver libs state
1011 Returns 1 when there were options (state needs to be restored later, see
1013 Returns 0 when there were no options;
1014 Returns -1 on error. */
1017 struct __res_state
*save_res
)
1019 if (sfd
->para
.socket
.ip
.res
.opts
[0] ||
1020 sfd
->para
.socket
.ip
.res
.opts
[1] ||
1021 #if HAVE_RES_RETRANS
1022 sfd
->para
.socket
.ip
.res
.retrans
>= 0 ||
1025 sfd
->para
.socket
.ip
.res
.retry
>= 0 ||
1027 #if HAVE_RES_NSADDR_LIST
1028 sfd
->para
.socket
.ip
.res
.nsaddr
.sin_family
!= PF_UNSPEC
||
1030 0 /* for canonical reasons */
1032 if (!(_res
.options
& RES_INIT
)) {
1033 if (Res_init() < 0) {
1034 Error("res_init() failed");
1039 _res
.options
|= sfd
->para
.socket
.ip
.res
.opts
[0];
1040 _res
.options
&= ~sfd
->para
.socket
.ip
.res
.opts
[1];
1041 Debug2("changed _res.options from 0x%lx to 0x%lx",
1042 save_res
->options
, _res
.options
);
1044 #if HAVE_RES_RETRANS
1045 if (sfd
->para
.socket
.ip
.res
.retrans
>= 0) {
1046 _res
.retrans
= sfd
->para
.socket
.ip
.res
.retrans
;
1047 Debug2("changed _res.retrans from 0x%x to 0x%x",
1048 save_res
->retrans
, _res
.retrans
);
1052 if (sfd
->para
.socket
.ip
.res
.retry
>= 0) {
1053 _res
.retry
= sfd
->para
.socket
.ip
.res
.retry
;
1054 Debug2("changed _res.retry from 0x%x to 0x%x",
1055 save_res
->retry
, _res
.retry
);
1058 #if HAVE_RES_NSADDR_LIST
1059 if (sfd
->para
.socket
.ip
.res
.nsaddr
.sin_family
== PF_INET
) {
1061 _res
.nsaddr_list
[0] = sfd
->para
.socket
.ip
.res
.nsaddr
;
1062 if (_res
.nsaddr_list
[0].sin_port
== htons(0))
1063 _res
.nsaddr_list
[0].sin_port
= htons(53);
1064 Debug10("changed _res.nsaddr_list[0] from %u.%u.%u.%u:%u to %u.%u.%u.%u:%u",
1065 ((unsigned char *)&save_res
->nsaddr_list
[0].sin_addr
.s_addr
)[0],
1066 ((unsigned char *)&save_res
->nsaddr_list
[0].sin_addr
.s_addr
)[1],
1067 ((unsigned char *)&save_res
->nsaddr_list
[0].sin_addr
.s_addr
)[2],
1068 ((unsigned char *)&save_res
->nsaddr_list
[0].sin_addr
.s_addr
)[3],
1069 ntohs(save_res
->nsaddr_list
[0].sin_port
),
1070 ((unsigned char *)&_res
.nsaddr_list
[0].sin_addr
.s_addr
)[0],
1071 ((unsigned char *)&_res
.nsaddr_list
[0].sin_addr
.s_addr
)[1],
1072 ((unsigned char *)&_res
.nsaddr_list
[0].sin_addr
.s_addr
)[2],
1073 ((unsigned char *)&_res
.nsaddr_list
[0].sin_addr
.s_addr
)[3],
1074 ntohs(_res
.nsaddr_list
[0].sin_port
));
1076 #endif /* HAVE_RES_NSADDR_LIST */
1084 int xio_res_restore(
1085 struct __res_state
*save_res
)
1090 #endif /* HAVE_RESOLV_H */
1091 #endif /* WITH_RESOLVE */
1093 #endif /* _WITH_IP4 || _WITH_IP6 */