1 /* source: xio-ip6.c */
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 IP6 related functions */
7 #include "xiosysincludes.h"
12 #include "xio-ascii.h"
13 #include "xio-socket.h"
14 #include "xio-ip.h" /* xiogetaddrinfo() */
19 static char *inet6addr_info(const struct in6_addr
*sa
, char *buff
, size_t blen
);
23 const struct optdesc opt_ipv6_v6only
= { "ipv6-v6only", "ipv6only", OPT_IPV6_V6ONLY
, GROUP_SOCK_IP6
, PH_PREBIND
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_V6ONLY
};
25 #ifdef IPV6_JOIN_GROUP
26 const struct optdesc opt_ipv6_join_group
= { "ipv6-join-group", "join-group", OPT_IPV6_JOIN_GROUP
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_IP_MREQN
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_JOIN_GROUP
};
29 const struct optdesc opt_ipv6_pktinfo
= { "ipv6-pktinfo", "pktinfo", OPT_IPV6_PKTINFO
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_PKTINFO
};
31 #ifdef IPV6_RECVPKTINFO
32 const struct optdesc opt_ipv6_recvpktinfo
= { "ipv6-recvpktinfo", "recvpktinfo", OPT_IPV6_RECVPKTINFO
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_RECVPKTINFO
};
35 const struct optdesc opt_ipv6_rthdr
= { "ipv6-rthdr", "rthdr", OPT_IPV6_RTHDR
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_RTHDR
};
38 const struct optdesc opt_ipv6_recvrthdr
= { "ipv6-recvrthdr", "recvrthdr", OPT_IPV6_RECVRTHDR
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_RECVRTHDR
};
41 const struct optdesc opt_ipv6_authhdr
= { "ipv6-authhdr", "authhdr", OPT_IPV6_AUTHHDR
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_AUTHHDR
};
44 const struct optdesc opt_ipv6_dstopts
= { "ipv6-dstopts", "dstopts", OPT_IPV6_DSTOPTS
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_DSTOPTS
};
46 #ifdef IPV6_RECVDSTOPTS
47 const struct optdesc opt_ipv6_recvdstopts
= { "ipv6-recvdstopts", "recvdstopts", OPT_IPV6_RECVDSTOPTS
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_RECVDSTOPTS
};
50 const struct optdesc opt_ipv6_hopopts
= { "ipv6-hopopts", "hopopts", OPT_IPV6_HOPOPTS
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_HOPOPTS
};
52 #ifdef IPV6_RECVHOPOPTS
53 const struct optdesc opt_ipv6_recvhopopts
= { "ipv6-recvhopopts", "recvhopopts", OPT_IPV6_RECVHOPOPTS
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_RECVHOPOPTS
};
55 #ifdef IPV6_FLOWINFO /* is in linux/in6.h */
56 const struct optdesc opt_ipv6_flowinfo
= { "ipv6-flowinfo","flowinfo",OPT_IPV6_FLOWINFO
,GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_FLOWINFO
};
59 const struct optdesc opt_ipv6_hoplimit
= { "ipv6-hoplimit","hoplimit",OPT_IPV6_HOPLIMIT
,GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_HOPLIMIT
};
61 const struct optdesc opt_ipv6_unicast_hops
= { "ipv6-unicast-hops","unicast-hops",OPT_IPV6_UNICAST_HOPS
,GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_UNICAST_HOPS
};
62 #ifdef IPV6_RECVHOPLIMIT
63 const struct optdesc opt_ipv6_recvhoplimit
= { "ipv6-recvhoplimit","recvhoplimit",OPT_IPV6_RECVHOPLIMIT
,GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_RECVHOPLIMIT
};
66 const struct optdesc opt_ipv6_recverr
= { "ipv6-recverr", "recverr", OPT_IPV6_RECVERR
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_RECVERR
};
69 const struct optdesc opt_ipv6_tclass
= { "ipv6-tclass", "tclass", OPT_IPV6_TCLASS
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_TCLASS
};
71 #ifdef IPV6_RECVTCLASS
72 const struct optdesc opt_ipv6_recvtclass
= { "ipv6-recvtclass", "recvtclass", OPT_IPV6_RECVTCLASS
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_RECVTCLASS
};
74 #ifdef IPV6_RECVPATHMTU
75 const struct optdesc opt_ipv6_recvpathmtu
= { "ipv6-recvpathmtu", "recvpathmtu", OPT_IPV6_RECVPATHMTU
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_INT
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_RECVPATHMTU
};
78 /* Returns canonical form of IPv6 address.
79 IPv6 address may bei enclose in brackets.
80 Returns STAT_OK on success, STAT_NORETRY on failure. */
81 int xioip6_pton(const char *src
, struct in6_addr
*dst
) {
82 union sockaddr_union sockaddr
;
83 socklen_t sockaddrlen
= sizeof(sockaddr
);
86 char plainaddr
[INET6_ADDRSTRLEN
];
89 strncpy(plainaddr
, src
+1, INET6_ADDRSTRLEN
);
90 plainaddr
[INET6_ADDRSTRLEN
-1] = '\0';
91 if ((clos
= strchr(plainaddr
, ']')) != NULL
)
93 return xioip6_pton(plainaddr
, dst
);
95 if (xiogetaddrinfo(src
, NULL
, PF_INET6
, 0, 0, &sockaddr
, &sockaddrlen
,
100 *dst
= sockaddr
.ip6
.sin6_addr
;
104 int xioparsenetwork_ip6(const char *rangename
, struct xiorange
*range
) {
105 char *delimpos
; /* absolute address of delimiter */
106 size_t delimind
; /* index of delimiter in string */
107 unsigned int bits
; /* netmask bits */
110 union sockaddr_union sockaddr
;
111 socklen_t sockaddrlen
= sizeof(sockaddr
);
112 union xioin6_u
*rangeaddr
= (union xioin6_u
*)&range
->netaddr
.ip6
.sin6_addr
;
113 union xioin6_u
*rangemask
= (union xioin6_u
*)&range
->netmask
.ip6
.sin6_addr
;
114 union xioin6_u
*nameaddr
= (union xioin6_u
*)&sockaddr
.ip6
.sin6_addr
;
116 if ((delimpos
= strchr(rangename
, '/')) == NULL
) {
117 Error1("xioparsenetwork_ip6(\"%s\",,): missing mask bits delimiter '/'",
121 delimind
= delimpos
- rangename
;
122 if (rangename
[0] != '[' || rangename
[delimind
-1] != ']') {
123 Error1("missing brackets for IPv6 range definition \"%s\"",
128 if ((baseaddr
= strndup(rangename
+1,delimind
-2)) == NULL
) {
129 Error1("strdup(\"%s\"): out of memory", rangename
+1);
132 baseaddr
[delimind
-2] = '\0';
133 if (xiogetaddrinfo(baseaddr
, NULL
, PF_INET6
, 0, 0, &sockaddr
, &sockaddrlen
,
138 rangeaddr
->u6_addr32
[0] = nameaddr
->u6_addr32
[0];
139 rangeaddr
->u6_addr32
[1] = nameaddr
->u6_addr32
[1];
140 rangeaddr
->u6_addr32
[2] = nameaddr
->u6_addr32
[2];
141 rangeaddr
->u6_addr32
[3] = nameaddr
->u6_addr32
[3];
142 bits
= strtoul(delimpos
+1, &endptr
, 10);
143 if (! ((*(delimpos
+1) != '\0') && (*endptr
== '\0'))) {
144 Error1("not a valid netmask in \"%s\"", rangename
);
145 bits
= 128; /* most secure selection */
146 } else if (bits
> 128) {
147 Error1("netmask \"%s\" is too large", rangename
);
151 /* I am starting to dislike C...uint32_t << 32 is undefined... */
153 rangemask
->u6_addr32
[0] = 0;
154 rangemask
->u6_addr32
[1] = 0;
155 rangemask
->u6_addr32
[2] = 0;
156 rangemask
->u6_addr32
[3] = 0;
157 } else if (bits
<= 32) {
158 rangemask
->u6_addr32
[0] = htonl(0xffffffff << (32-bits
));
159 rangemask
->u6_addr32
[1] = 0;
160 rangemask
->u6_addr32
[2] = 0;
161 rangemask
->u6_addr32
[3] = 0;
162 } else if (bits
<= 64) {
163 rangemask
->u6_addr32
[0] = 0xffffffff;
164 rangemask
->u6_addr32
[1] = htonl(0xffffffff << (64-bits
));
165 rangemask
->u6_addr32
[2] = 0;
166 rangemask
->u6_addr32
[3] = 0;
167 } else if (bits
<= 96) {
168 rangemask
->u6_addr32
[0] = 0xffffffff;
169 rangemask
->u6_addr32
[1] = 0xffffffff;
170 rangemask
->u6_addr32
[2] = htonl(0xffffffff << (96-bits
));
171 rangemask
->u6_addr32
[3] = 0;
173 rangemask
->u6_addr32
[0] = 0xffffffff;
174 rangemask
->u6_addr32
[1] = 0xffffffff;
175 rangemask
->u6_addr32
[2] = 0xffffffff;
176 rangemask
->u6_addr32
[3] = htonl(0xffffffff << (128-bits
));
181 int xiorange_ip6andmask(struct xiorange
*range
) {
184 range
->addr
.s6_addr32
[0] &= range
->mask
.s6_addr32
[0];
185 range
->addr
.s6_addr32
[1] &= range
->mask
.s6_addr32
[1];
186 range
->addr
.s6_addr32
[2] &= range
->mask
.s6_addr32
[2];
187 range
->addr
.s6_addr32
[3] &= range
->mask
.s6_addr32
[3];
189 for (i
= 0; i
< 16; ++i
) {
190 range
->netaddr
.ip6
.sin6_addr
.s6_addr
[i
] &=
191 range
->netmask
.ip6
.sin6_addr
.s6_addr
[i
];
197 /* check if peer address is within permitted range.
198 return >= 0 if so. */
199 int xiocheckrange_ip6(struct sockaddr_in6
*pa
, struct xiorange
*range
) {
200 union xioin6_u masked
;
203 union xioin6_u
*rangeaddr
= (union xioin6_u
*)&range
->netaddr
.ip6
.sin6_addr
;
204 union xioin6_u
*rangemask
= (union xioin6_u
*)&range
->netmask
.ip6
.sin6_addr
;
206 Debug16("permitted client subnet: [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
207 htons(rangeaddr
->u6_addr16
[0]), htons(rangeaddr
->u6_addr16
[1]),
208 htons(rangeaddr
->u6_addr16
[2]), htons(rangeaddr
->u6_addr16
[3]),
209 htons(rangeaddr
->u6_addr16
[4]), htons(rangeaddr
->u6_addr16
[5]),
210 htons(rangeaddr
->u6_addr16
[6]), htons(rangeaddr
->u6_addr16
[7]),
211 htons(rangemask
->u6_addr16
[0]), htons(rangemask
->u6_addr16
[1]),
212 htons(rangemask
->u6_addr16
[2]), htons(rangemask
->u6_addr16
[3]),
213 htons(rangemask
->u6_addr16
[4]), htons(rangemask
->u6_addr16
[5]),
214 htons(rangemask
->u6_addr16
[6]), htons(rangemask
->u6_addr16
[7]));
215 Debug1("client address is %s",
216 sockaddr_inet6_info(pa
, peername
, sizeof(peername
)));
218 for (i
= 0; i
< 4; ++i
) {
219 masked
.u6_addr32
[i
] = ((union xioin6_u
*)&pa
->sin6_addr
.s6_addr
[0])->u6_addr32
[i
] & rangemask
->u6_addr32
[i
];
221 Debug8("masked address is [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
222 htons(masked
.u6_addr16
[0]), htons(masked
.u6_addr16
[1]),
223 htons(masked
.u6_addr16
[2]), htons(masked
.u6_addr16
[3]),
224 htons(masked
.u6_addr16
[4]), htons(masked
.u6_addr16
[5]),
225 htons(masked
.u6_addr16
[6]), htons(masked
.u6_addr16
[7]));
227 if (masked
.u6_addr32
[0] != rangeaddr
->u6_addr32
[0] ||
228 masked
.u6_addr32
[1] != rangeaddr
->u6_addr32
[1] ||
229 masked
.u6_addr32
[2] != rangeaddr
->u6_addr32
[2] ||
230 masked
.u6_addr32
[3] != rangeaddr
->u6_addr32
[3]) {
231 Debug1("client address %s is not permitted", peername
);
238 #if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
239 /* provides info about the ancillary message:
240 converts the ancillary message in *cmsg into a form useable for further
241 processing. knows the specifics of common message types.
242 returns the number of resulting syntax elements in *num
243 returns a sequence of \0 terminated type strings in *typbuff
244 returns a sequence of \0 terminated name strings in *nambuff
245 returns a sequence of \0 terminated value strings in *valbuff
246 the respective len parameters specify the available space in the buffers
247 returns STAT_OK on success
249 int xiolog_ancillary_ip6(struct cmsghdr
*cmsg
, int *num
,
250 char *typbuff
, int typlen
,
251 char *nambuff
, int namlen
,
252 char *envbuff
, int envlen
,
253 char *valbuff
, int vallen
) {
254 char scratch1
[42]; /* can hold an IPv6 address in ASCII */
258 *num
= 1; /* good for most message types */
259 msglen
= cmsg
->cmsg_len
-((char *)CMSG_DATA(cmsg
)-(char *)cmsg
);
261 switch (cmsg
->cmsg_type
) {
262 #if defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO
264 struct in6_pktinfo
*pktinfo
= (struct in6_pktinfo
*)CMSG_DATA(cmsg
);
266 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_PKTINFO", typlen
-1);
267 snprintf(nambuff
, namlen
, "%s%c%s", "dstaddr", '\0', "if");
268 snprintf(envbuff
, envlen
, "%s%c%s", "IPV6_DSTADDR", '\0', "IPV6_IF");
269 snprintf(valbuff
, vallen
, "%s%c%s",
270 inet6addr_info(&pktinfo
->ipi6_addr
, scratch1
, sizeof(scratch1
)),
271 '\0', xiogetifname(pktinfo
->ipi6_ifindex
, scratch2
, -1));
274 #endif /* defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO */
277 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_HOPLIMIT", typlen
-1);
278 nambuff
[0] = '\0'; strncat(nambuff
, "hoplimit", namlen
-1);
280 int *intp
= (int *)CMSG_DATA(cmsg
);
281 snprintf(valbuff
, vallen
, "%d", *intp
);
284 #endif /* defined(IPV6_HOPLIMIT) */
287 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_RTHDR", typlen
-1);
288 nambuff
[0] = '\0'; strncat(nambuff
, "rthdr", namlen
-1);
289 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
291 #endif /* defined(IPV6_RTHDR) */
294 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_AUTHHDR", typlen
-1);
295 nambuff
[0] = '\0'; strncat(nambuff
, "authhdr", namlen
-1);
296 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
301 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_DSTOPTS", typlen
-1);
302 nambuff
[0] = '\0'; strncat(nambuff
, "dstopts", namlen
-1);
303 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
305 #endif /* defined(IPV6_DSTOPTS) */
308 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_HOPOPTS", typlen
-1);
309 nambuff
[0] = '\0'; strncat(nambuff
, "hopopts", namlen
-1);
310 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
312 #endif /* defined(IPV6_HOPOPTS) */
315 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_FLOWINFO", typlen
-1);
316 nambuff
[0] = '\0'; strncat(nambuff
, "flowinfo", namlen
-1);
317 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
323 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_TCLASS", typlen
-1);
324 nambuff
[0] = '\0'; strncat(nambuff
, "tclass", namlen
-1);
325 u
= ntohl(*(unsigned int *)CMSG_DATA(cmsg
));
326 xiodump((const unsigned char *)&u
, msglen
, valbuff
, vallen
, 0);
331 snprintf(typbuff
, typlen
, "IPV6.%u", cmsg
->cmsg_type
);
332 nambuff
[0] = '\0'; strncat(nambuff
, "data", namlen
-1);
333 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
338 #endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */
341 /* convert the IP6 socket address to human readable form. buff should be at
342 least 50 chars long. output includes the port number */
343 static char *inet6addr_info(const struct in6_addr
*sa
, char *buff
, size_t blen
) {
344 if (xio_snprintf(buff
, blen
, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
345 #if HAVE_IP6_SOCKADDR==0
346 (sa
->s6_addr
[0]<<8)+sa
->s6_addr
[1],
347 (sa
->s6_addr
[2]<<8)+sa
->s6_addr
[3],
348 (sa
->s6_addr
[4]<<8)+sa
->s6_addr
[5],
349 (sa
->s6_addr
[6]<<8)+sa
->s6_addr
[7],
350 (sa
->s6_addr
[8]<<8)+sa
->s6_addr
[9],
351 (sa
->s6_addr
[10]<<8)+sa
->s6_addr
[11],
352 (sa
->s6_addr
[12]<<8)+sa
->s6_addr
[13],
353 (sa
->s6_addr
[14]<<8)+sa
->s6_addr
[15]
354 #elif HAVE_IP6_SOCKADDR==1
355 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[0]),
356 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[1]),
357 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[2]),
358 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[3]),
359 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[4]),
360 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[5]),
361 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[6]),
362 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[7])
363 #elif HAVE_IP6_SOCKADDR==2
364 ntohs(((unsigned short *)&sa
->u6_addr16
)[0]),
365 ntohs(((unsigned short *)&sa
->u6_addr16
)[1]),
366 ntohs(((unsigned short *)&sa
->u6_addr16
)[2]),
367 ntohs(((unsigned short *)&sa
->u6_addr16
)[3]),
368 ntohs(((unsigned short *)&sa
->u6_addr16
)[4]),
369 ntohs(((unsigned short *)&sa
->u6_addr16
)[5]),
370 ntohs(((unsigned short *)&sa
->u6_addr16
)[6]),
371 ntohs(((unsigned short *)&sa
->u6_addr16
)[7])
372 #elif HAVE_IP6_SOCKADDR==3
373 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[0]),
374 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[1]),
375 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[2]),
376 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[3]),
377 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[4]),
378 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[5]),
379 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[6]),
380 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[7])
381 #elif HAVE_IP6_SOCKADDR==4
382 (sa
->_S6_un
._S6_u8
[0]<<8)|(sa
->_S6_un
._S6_u8
[1]&0xff),
383 (sa
->_S6_un
._S6_u8
[2]<<8)|(sa
->_S6_un
._S6_u8
[3]&0xff),
384 (sa
->_S6_un
._S6_u8
[4]<<8)|(sa
->_S6_un
._S6_u8
[5]&0xff),
385 (sa
->_S6_un
._S6_u8
[6]<<8)|(sa
->_S6_un
._S6_u8
[7]&0xff),
386 (sa
->_S6_un
._S6_u8
[8]<<8)|(sa
->_S6_un
._S6_u8
[9]&0xff),
387 (sa
->_S6_un
._S6_u8
[10]<<8)|(sa
->_S6_un
._S6_u8
[11]&0xff),
388 (sa
->_S6_un
._S6_u8
[12]<<8)|(sa
->_S6_un
._S6_u8
[13]&0xff),
389 (sa
->_S6_un
._S6_u8
[14]<<8)|(sa
->_S6_un
._S6_u8
[15]&0xff)
390 #elif HAVE_IP6_SOCKADDR==5
391 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[0]),
392 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[1]),
393 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[2]),
394 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[3]),
395 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[4]),
396 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[5]),
397 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[6]),
398 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[7])
401 Warn("sockaddr_inet6_info(): buffer too short");
408 /* returns information that can be used for constructing an environment
409 variable describing the socket address.
410 if idx is 0, this function writes "ADDR" into namebuff and the IP address
411 into valuebuff, and returns 1 (which means that one more info is there).
412 if idx is 1, it writes "PORT" into namebuff and the port number into
413 valuebuff, and returns 0 (no more info)
414 namelen and valuelen contain the max. allowed length of output chars in the
416 on error this function returns -1.
419 xiosetsockaddrenv_ip6(int idx
, char *namebuff
, size_t namelen
,
420 char *valuebuff
, size_t valuelen
,
421 struct sockaddr_in6
*sa
, int ipproto
) {
424 strcpy(namebuff
, "ADDR");
425 snprintf(valuebuff
, valuelen
, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
426 (sa
->sin6_addr
.s6_addr
[0]<<8)+
427 sa
->sin6_addr
.s6_addr
[1],
428 (sa
->sin6_addr
.s6_addr
[2]<<8)+
429 sa
->sin6_addr
.s6_addr
[3],
430 (sa
->sin6_addr
.s6_addr
[4]<<8)+
431 sa
->sin6_addr
.s6_addr
[5],
432 (sa
->sin6_addr
.s6_addr
[6]<<8)+
433 sa
->sin6_addr
.s6_addr
[7],
434 (sa
->sin6_addr
.s6_addr
[8]<<8)+
435 sa
->sin6_addr
.s6_addr
[9],
436 (sa
->sin6_addr
.s6_addr
[10]<<8)+
437 sa
->sin6_addr
.s6_addr
[11],
438 (sa
->sin6_addr
.s6_addr
[12]<<8)+
439 sa
->sin6_addr
.s6_addr
[13],
440 (sa
->sin6_addr
.s6_addr
[14]<<8)+
441 sa
->sin6_addr
.s6_addr
[15]);
448 return 1; /* there is port information to also be retrieved */
450 return 0; /* no port info coming */
453 strcpy(namebuff
, "PORT");
454 snprintf(valuebuff
, valuelen
, "%u", ntohs(sa
->sin6_port
));
460 #endif /* WITH_IP6 */