2 /* Copyright Gerhard Rieger */
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"
19 #if WITH_IP4 || WITH_IP6
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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 */
89 #endif /* WITH_IP4 || WITH_IP6 */
97 Debug1("res_init() -> %d", result
);
100 #endif /* HAVE_RESOLV_H */
103 unsigned long res_opts() {
106 #endif /* HAVE_RESOLV_H */
108 /* the ultimate(?) socat resolver function
109 node: the address to be resolved; supported forms:
110 1.2.3.4 (IPv4 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
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
;
128 unsigned long save_res_opts
= 0;
130 struct addrinfo hints
= {0};
131 struct addrinfo
*res
= NULL
;
132 #else /* HAVE_PROTOTYPE_LIB_getipnodebyname || nothing */
133 struct hostent
*host
;
138 if (res_opts0
| res_opts1
) {
139 if (!(_res
.options
& RES_INIT
)) {
140 Res_init(); /*!!! returns -1 on error */
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
);
148 #endif /* HAVE_RESOLV_H */
149 memset(sau
, 0, *socklen
);
150 sau
->soa
.sa_family
= family
;
152 if (service
&& service
[0]=='\0') {
153 Error("empty port/service");
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)) {
159 port
= htons(strtoul(service
, &extra
, 0));
160 if (*extra
!= '\0') {
161 Warn2("xiogetaddrinfo(, \"%s\", ...): extra trailing data \"%s\"",
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)) {
172 hints
.ai_flags
|= AI_NUMERICHOST
;
173 #endif /* HAVE_GETADDRINFO */
174 if (family
== PF_UNSPEC
) {
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
) {
182 if (res_opts0
| res_opts1
) {
183 _res
.options
= (_res
.options
& (~res_opts0
&~res_opts1
) |
184 save_res_opts
& ( res_opts0
| res_opts1
));
189 sprintf(numnode
, "::ffff:%s", node
);
191 hints
.ai_flags
|= AI_NUMERICHOST
;
192 #endif /* HAVE_GETADDRINFO */
195 } else if (node
&& node
[0] == '[' && node
[(nodelen
=strlen(node
))-1]==']') {
196 if ((numnode
= Malloc(nodelen
-1)) == NULL
) {
198 if (res_opts0
| res_opts1
) {
199 _res
.options
= (_res
.options
& (~res_opts0
&~res_opts1
) |
200 save_res_opts
& ( res_opts0
| res_opts1
));
205 strncpy(numnode
, node
+1, nodelen
-2); /* ok */
206 numnode
[nodelen
-2] = '\0';
209 hints
.ai_flags
|= AI_NUMERICHOST
;
210 #endif /* HAVE_GETADDRINFO */
211 if (family
== PF_UNSPEC
) family
= PF_INET6
;
212 #endif /* WITH_IP6 */
216 if (node
!= NULL
|| service
!= NULL
) {
217 struct addrinfo
*record
;
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
;
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
;
228 protocol
= IPPROTO_TCP
;
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
;
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
);
250 if (res_opts0
| res_opts1
) {
251 _res
.options
= (_res
.options
& (~res_opts0
&~res_opts1
) |
252 save_res_opts
& ( res_opts0
| res_opts1
));
255 return STAT_RETRYLATER
;
257 service
= NULL
; /* do not resolve later again */
260 if (family
== PF_UNSPEC
&& xioopts
.preferred_ip
== '0') {
261 /* we just take the first result */
262 family
= res
[0].ai_addr
->sa_family
;
264 if (family
== PF_UNSPEC
) {
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
) {
271 break; /* family and record set accordingly */
273 record
= record
->ai_next
;
275 if (record
== NULL
) {
276 /* we did not find a "preferred" entry, take the first */
278 family
= res
[0].ai_addr
->sa_family
;
285 if (*socklen
> record
->ai_addrlen
) {
286 *socklen
= record
->ai_addrlen
;
288 memcpy(&sau
->ip4
, record
->ai_addr
, *socklen
);
290 #endif /* WITH_IP4 */
294 /* older AIX versions pass wrong length, so we correct it */
295 record
->ai_addr
->sa_len
= sizeof(struct sockaddr_in6
);
297 if (*socklen
> record
->ai_addrlen
) {
298 *socklen
= record
->ai_addrlen
;
300 memcpy(&sau
->ip6
, record
->ai_addr
, *socklen
);
302 #endif /* WITH_IP6 */
304 Error1("address resolved to unknown protocol family %d",
305 record
->ai_addr
->sa_family
);
312 case PF_INET
: *socklen
= sizeof(sau
->ip4
); break;
313 #endif /* WITH_IP4 */
315 case PF_INET6
: *socklen
= sizeof(sau
->ip6
); break;
316 #endif /* WITH_IP6 */
320 #elif HAVE_PROTOTYPE_LIB_getipnodebyname /* !HAVE_GETADDRINFO */
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
;
333 host
= Getipnodebyname(node
, family
, AI_V4MAPPED
, &error_num
);
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";
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
;
346 Error2("getipnodebyname(\"%s\", ...): %s", node
, error_msg
);
351 *socklen
= sizeof(sau
->ip4
);
352 sau
->soa
.sa_family
= PF_INET
;
353 memcpy(&sau
->ip4
.sin_addr
, host
->h_addr_list
[0], 4);
358 *socklen
= sizeof(sau
->ip6
);
359 sau
->soa
.sa_family
= PF_INET6
;
360 memcpy(&sau
->ip6
.sin6_addr
, host
->h_addr_list
[0], 16);
368 #else /* !HAVE_PROTOTYPE_LIB_getipnodebyname */
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
;
384 /*!!! try gethostbyname2 for IP6 */
385 if ((host
= Gethostbyname(node
)) == NULL
) {
386 Error2("gethostbyname(\"%s\"): %s", node
,
387 h_errno
== NETDB_INTERNAL
? strerror(errno
) :
390 if (res_opts0
| res_opts1
) {
391 _res
.options
= (_res
.options
& (~res_opts0
&~res_opts1
) |
392 save_res_opts
& ( res_opts0
| res_opts1
));
395 return STAT_RETRYLATER
;
397 if (host
->h_addrtype
!= family
) {
398 Error2("xioaddrinfo(): \"%s\" does not resolve to %s",
399 node
, family
==PF_INET
?"IP4":"IP6");
404 *socklen
= sizeof(sau
->ip4
);
405 sau
->soa
.sa_family
= PF_INET
;
406 memcpy(&sau
->ip4
.sin_addr
, host
->h_addr_list
[0], 4);
408 #endif /* WITH_IP4 */
411 *socklen
= sizeof(sau
->ip6
);
412 sau
->soa
.sa_family
= PF_INET6
;
413 memcpy(&sau
->ip6
.sin6_addr
, host
->h_addr_list
[0], 16);
415 #endif /* WITH_IP6 */
422 #if WITH_TCP || WITH_UDP
424 port
= parseport(service
, protocol
);
429 case PF_INET
: sau
->ip4
.sin_port
= port
; break;
430 #endif /* WITH_IP4 */
432 case PF_INET6
: sau
->ip6
.sin6_port
= port
; break;
433 #endif /* WITH_IP6 */
436 #endif /* WITH_TCP || WITH_UDP */
438 if (numnode
) free(numnode
);
441 if (res_opts0
| res_opts1
) {
442 _res
.options
= (_res
.options
& (~res_opts0
&~res_opts1
) |
443 save_res_opts
& ( res_opts0
| res_opts1
));
445 #endif /* HAVE_RESOLV_H */
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.
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
;
469 char scratch1
[16]; /* can hold an IPv4 address in ASCII */
470 #if WITH_IP4 && defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO
476 msglen
= cmsg
->cmsg_len
-((char *)CMSG_DATA(cmsg
)-(char *)cmsg
);
478 switch (cmsg
->cmsg_type
) {
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);
486 #if defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO
488 struct in_pktinfo
*pktinfo
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
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
)),
503 inet4addr_info(ntohl(pktinfo
->ipi_addr
.s_addr
),
504 scratch3
, sizeof(scratch3
)));
507 #endif /* defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO */
508 #endif /* WITH_IP4 */
509 #if defined(IP_RECVERR) && HAVE_STRUCT_SOCK_EXTENDED_ERR
511 struct sock_extended_err
*err
=
512 (struct sock_extended_err
*)CMSG_DATA(cmsg
);
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
);
527 #endif /* defined(IP_RECVERR) && HAVE_STRUCT_SOCK_EXTENDED_ERR */
530 /* spec in FreeBSD: /usr/include/net/if_dl.h */
531 struct sockaddr_dl
*sadl
= (struct sockaddr_dl
*)CMSG_DATA(cmsg
);
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);
538 xiosubstr(scratch1
, sadl
->sdl_data
, 0, sadl
->sdl_nlen
), vallen
-1);
541 #endif /* defined(IP_RECVIF) */
543 #ifdef IP_RECVDSTADDR
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
);
552 #endif /* WITH_IP4 */
557 cmsgtype
= "IP_OPTIONS"; cmsgname
= "options"; cmsgfmt
= NULL
; break;
559 cmsgtype
= "IP_TOS"; cmsgname
= "tos"; cmsgfmt
= "%u"; break;
560 case IP_TTL
: /* Linux */
562 case IP_RECVTTL
: /* FreeBSD */
564 cmsgtype
= "IP_TTL"; cmsgname
= "ttl"; cmsgfmt
= "%u"; break;
566 /* when we come here we provide a single parameter
567 with type in cmsgtype, name in cmsgname, printf format in cmsgfmt */
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);
574 if (strlen(cmsgenvn
) >= envlen
) rc
= STAT_WARNING
;
575 envbuff
[0] = '\0'; strncat(envbuff
, cmsgenvn
, envlen
-1);
579 if (cmsgfmt
!= NULL
) {
580 snprintf(valbuff
, vallen
, cmsgfmt
, *(unsigned char *)CMSG_DATA(cmsg
));
582 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
586 #endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */
588 #endif /* _WITH_IP4 || _WITH_IP6 */