1 /* source: xio-ip6.c */
2 /* Copyright Gerhard Rieger */
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_BOOL
, 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_PASTBIND
, 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_BOOL
, 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_BOOL
, 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_BOOL
, 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_BOOL
, 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_BOOL
, 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_BOOL
, 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_BOOL
, 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_BOOL
, 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_BOOL
, 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_BOOL
, 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_BOOL
, 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_BOOL
, 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_BOOL
, 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_BOOL
, 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_BOOL
, OFUNC_SOCKOPT
, SOL_IPV6
, IPV6_RECVPATHMTU
};
78 int xioparsenetwork_ip6(const char *rangename
, struct xiorange
*range
) {
79 char *delimpos
; /* absolute address of delimiter */
80 size_t delimind
; /* index of delimiter in string */
81 unsigned int bits
; /* netmask bits */
84 union sockaddr_union sockaddr
;
85 socklen_t sockaddrlen
= sizeof(sockaddr
);
86 union xioin6_u
*rangeaddr
= (union xioin6_u
*)&range
->netaddr
.ip6
.sin6_addr
;
87 union xioin6_u
*rangemask
= (union xioin6_u
*)&range
->netmask
.ip6
.sin6_addr
;
88 union xioin6_u
*nameaddr
= (union xioin6_u
*)&sockaddr
.ip6
.sin6_addr
;
90 if (rangename
[0] != '[' || rangename
[strlen(rangename
)-1] != ']') {
91 Error1("missing brackets for IPv6 range definition \"%s\"",
95 if ((delimpos
= strchr(rangename
, '/')) == NULL
) {
96 Error1("xioparsenetwork_ip6(\"%s\",,): missing mask bits delimiter '/'",
100 delimind
= delimpos
- rangename
;
102 if ((baseaddr
= strdup(rangename
+1)) == NULL
) {
103 Error1("strdup(\"%s\"): out of memory", rangename
+1);
106 baseaddr
[delimind
-1] = '\0';
107 if (xiogetaddrinfo(baseaddr
, NULL
, PF_INET6
, 0, 0, &sockaddr
, &sockaddrlen
,
112 rangeaddr
->u6_addr32
[0] = nameaddr
->u6_addr32
[0];
113 rangeaddr
->u6_addr32
[1] = nameaddr
->u6_addr32
[1];
114 rangeaddr
->u6_addr32
[2] = nameaddr
->u6_addr32
[2];
115 rangeaddr
->u6_addr32
[3] = nameaddr
->u6_addr32
[3];
116 bits
= strtoul(delimpos
+1, &endptr
, 10);
117 if (! ((*(delimpos
+1) != '\0') && (*endptr
== '\0'))) {
118 Error1("not a valid netmask in \"%s\"", rangename
);
119 bits
= 128; /* most secure selection */
120 } else if (bits
> 128) {
121 Error1("netmask \"%s\" is too large", rangename
);
125 /* I am starting to dislike C...uint32_t << 32 is undefined... */
127 rangemask
->u6_addr32
[0] = 0;
128 rangemask
->u6_addr32
[1] = 0;
129 rangemask
->u6_addr32
[2] = 0;
130 rangemask
->u6_addr32
[3] = 0;
131 } else if (bits
<= 32) {
132 rangemask
->u6_addr32
[0] = htonl(0xffffffff << (32-bits
));
133 rangemask
->u6_addr32
[1] = 0;
134 rangemask
->u6_addr32
[2] = 0;
135 rangemask
->u6_addr32
[3] = 0;
136 } else if (bits
<= 64) {
137 rangemask
->u6_addr32
[0] = 0xffffffff;
138 rangemask
->u6_addr32
[1] = htonl(0xffffffff << (64-bits
));
139 rangemask
->u6_addr32
[2] = 0;
140 rangemask
->u6_addr32
[3] = 0;
141 } else if (bits
<= 96) {
142 rangemask
->u6_addr32
[0] = 0xffffffff;
143 rangemask
->u6_addr32
[1] = 0xffffffff;
144 rangemask
->u6_addr32
[2] = htonl(0xffffffff << (96-bits
));
145 rangemask
->u6_addr32
[3] = 0;
147 rangemask
->u6_addr32
[0] = 0xffffffff;
148 rangemask
->u6_addr32
[1] = 0xffffffff;
149 rangemask
->u6_addr32
[2] = 0xffffffff;
150 rangemask
->u6_addr32
[3] = htonl(0xffffffff << (128-bits
));
155 int xiorange_ip6andmask(struct xiorange
*range
) {
158 range
->addr
.s6_addr32
[0] &= range
->mask
.s6_addr32
[0];
159 range
->addr
.s6_addr32
[1] &= range
->mask
.s6_addr32
[1];
160 range
->addr
.s6_addr32
[2] &= range
->mask
.s6_addr32
[2];
161 range
->addr
.s6_addr32
[3] &= range
->mask
.s6_addr32
[3];
163 for (i
= 0; i
< 16; ++i
) {
164 range
->netaddr
.ip6
.sin6_addr
.s6_addr
[i
] &=
165 range
->netmask
.ip6
.sin6_addr
.s6_addr
[i
];
171 /* check if peer address is within permitted range.
172 return >= 0 if so. */
173 int xiocheckrange_ip6(struct sockaddr_in6
*pa
, struct xiorange
*range
) {
174 union xioin6_u masked
;
177 union xioin6_u
*rangeaddr
= (union xioin6_u
*)&range
->netaddr
.ip6
.sin6_addr
;
178 union xioin6_u
*rangemask
= (union xioin6_u
*)&range
->netmask
.ip6
;
180 Debug16("permitted client subnet: [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
181 htons(rangeaddr
->u6_addr16
[0]), htons(rangeaddr
->u6_addr16
[1]),
182 htons(rangeaddr
->u6_addr16
[2]), htons(rangeaddr
->u6_addr16
[3]),
183 htons(rangeaddr
->u6_addr16
[4]), htons(rangeaddr
->u6_addr16
[5]),
184 htons(rangeaddr
->u6_addr16
[6]), htons(rangeaddr
->u6_addr16
[7]),
185 htons(rangemask
->u6_addr16
[0]), htons(rangemask
->u6_addr16
[1]),
186 htons(rangemask
->u6_addr16
[2]), htons(rangemask
->u6_addr16
[3]),
187 htons(rangemask
->u6_addr16
[4]), htons(rangemask
->u6_addr16
[5]),
188 htons(rangemask
->u6_addr16
[6]), htons(rangemask
->u6_addr16
[7]));
189 Debug1("client address is %s",
190 sockaddr_inet6_info(pa
, peername
, sizeof(peername
)));
192 for (i
= 0; i
< 4; ++i
) {
193 masked
.u6_addr32
[i
] = pa
->sin6_addr
.s6_addr
[i
] & rangemask
->u6_addr16
[i
];
195 Debug8("masked address is [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
196 htons(masked
.u6_addr16
[0]), htons(masked
.u6_addr16
[1]),
197 htons(masked
.u6_addr16
[2]), htons(masked
.u6_addr16
[3]),
198 htons(masked
.u6_addr16
[4]), htons(masked
.u6_addr16
[5]),
199 htons(masked
.u6_addr16
[6]), htons(masked
.u6_addr16
[7]));
201 if (masked
.u6_addr32
[0] != rangeaddr
->u6_addr32
[0] ||
202 masked
.u6_addr32
[1] != rangeaddr
->u6_addr32
[1] ||
203 masked
.u6_addr32
[2] != rangeaddr
->u6_addr32
[2] ||
204 masked
.u6_addr32
[3] != rangeaddr
->u6_addr32
[3]) {
205 Debug1("client address %s is not permitted", peername
);
212 #if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
213 /* provides info about the ancillary message:
214 converts the ancillary message in *cmsg into a form useable for further
215 processing. knows the specifics of common message types.
216 returns the number of resulting syntax elements in *num
217 returns a sequence of \0 terminated type strings in *typbuff
218 returns a sequence of \0 terminated name strings in *nambuff
219 returns a sequence of \0 terminated value strings in *valbuff
220 the respective len parameters specify the available space in the buffers
221 returns STAT_OK on success
223 int xiolog_ancillary_ip6(struct cmsghdr
*cmsg
, int *num
,
224 char *typbuff
, int typlen
,
225 char *nambuff
, int namlen
,
226 char *envbuff
, int envlen
,
227 char *valbuff
, int vallen
) {
228 char scratch1
[42]; /* can hold an IPv6 address in ASCII */
232 *num
= 1; /* good for most message types */
233 msglen
= cmsg
->cmsg_len
-((char *)CMSG_DATA(cmsg
)-(char *)cmsg
);
235 switch (cmsg
->cmsg_type
) {
236 #if defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO
238 struct in6_pktinfo
*pktinfo
= (struct in6_pktinfo
*)CMSG_DATA(cmsg
);
240 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_PKTINFO", typlen
-1);
241 snprintf(nambuff
, namlen
, "%s%c%s", "dstaddr", '\0', "if");
242 snprintf(envbuff
, envlen
, "%s%c%s", "IPV6_DSTADDR", '\0', "IPV6_IF");
243 snprintf(valbuff
, vallen
, "%s%c%s",
244 inet6addr_info(&pktinfo
->ipi6_addr
, scratch1
, sizeof(scratch1
)),
245 '\0', xiogetifname(pktinfo
->ipi6_ifindex
, scratch2
, -1));
248 #endif /* defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO */
251 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_HOPLIMIT", typlen
-1);
252 nambuff
[0] = '\0'; strncat(nambuff
, "hoplimit", namlen
-1);
254 int *intp
= (int *)CMSG_DATA(cmsg
);
255 snprintf(valbuff
, vallen
, "%d", *intp
);
258 #endif /* defined(IPV6_HOPLIMIT) */
261 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_RTHDR", typlen
-1);
262 nambuff
[0] = '\0'; strncat(nambuff
, "rthdr", namlen
-1);
263 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
265 #endif /* defined(IPV6_RTHDR) */
268 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_AUTHHDR", typlen
-1);
269 nambuff
[0] = '\0'; strncat(nambuff
, "authhdr", namlen
-1);
270 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
275 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_DSTOPTS", typlen
-1);
276 nambuff
[0] = '\0'; strncat(nambuff
, "dstopts", namlen
-1);
277 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
279 #endif /* defined(IPV6_DSTOPTS) */
282 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_HOPOPTS", typlen
-1);
283 nambuff
[0] = '\0'; strncat(nambuff
, "hopopts", namlen
-1);
284 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
286 #endif /* defined(IPV6_HOPOPTS) */
289 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_FLOWINFO", typlen
-1);
290 nambuff
[0] = '\0'; strncat(nambuff
, "flowinfo", namlen
-1);
291 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
296 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_TCLASS", typlen
-1);
297 nambuff
[0] = '\0'; strncat(nambuff
, "tclass", namlen
-1);
298 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
302 snprintf(typbuff
, typlen
, "IPV6.%u", cmsg
->cmsg_type
);
303 nambuff
[0] = '\0'; strncat(nambuff
, "data", namlen
-1);
304 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
309 #endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */
312 /* convert the IP6 socket address to human readable form. buff should be at
313 least 50 chars long. output includes the port number */
314 static char *inet6addr_info(const struct in6_addr
*sa
, char *buff
, size_t blen
) {
315 if (xio_snprintf(buff
, blen
, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
316 #if HAVE_IP6_SOCKADDR==0
317 (sa
->s6_addr
[0]<<8)+sa
->s6_addr
[1],
318 (sa
->s6_addr
[2]<<8)+sa
->s6_addr
[3],
319 (sa
->s6_addr
[4]<<8)+sa
->s6_addr
[5],
320 (sa
->s6_addr
[6]<<8)+sa
->s6_addr
[7],
321 (sa
->s6_addr
[8]<<8)+sa
->s6_addr
[9],
322 (sa
->s6_addr
[10]<<8)+sa
->s6_addr
[11],
323 (sa
->s6_addr
[12]<<8)+sa
->s6_addr
[13],
324 (sa
->s6_addr
[14]<<8)+sa
->s6_addr
[15]
325 #elif HAVE_IP6_SOCKADDR==1
326 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[0]),
327 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[1]),
328 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[2]),
329 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[3]),
330 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[4]),
331 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[5]),
332 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[6]),
333 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[7])
334 #elif HAVE_IP6_SOCKADDR==2
335 ntohs(((unsigned short *)&sa
->u6_addr16
)[0]),
336 ntohs(((unsigned short *)&sa
->u6_addr16
)[1]),
337 ntohs(((unsigned short *)&sa
->u6_addr16
)[2]),
338 ntohs(((unsigned short *)&sa
->u6_addr16
)[3]),
339 ntohs(((unsigned short *)&sa
->u6_addr16
)[4]),
340 ntohs(((unsigned short *)&sa
->u6_addr16
)[5]),
341 ntohs(((unsigned short *)&sa
->u6_addr16
)[6]),
342 ntohs(((unsigned short *)&sa
->u6_addr16
)[7])
343 #elif HAVE_IP6_SOCKADDR==3
344 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[0]),
345 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[1]),
346 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[2]),
347 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[3]),
348 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[4]),
349 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[5]),
350 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[6]),
351 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[7])
352 #elif HAVE_IP6_SOCKADDR==4
353 (sa
->_S6_un
._S6_u8
[0]<<8)|(sa
->_S6_un
._S6_u8
[1]&0xff),
354 (sa
->_S6_un
._S6_u8
[2]<<8)|(sa
->_S6_un
._S6_u8
[3]&0xff),
355 (sa
->_S6_un
._S6_u8
[4]<<8)|(sa
->_S6_un
._S6_u8
[5]&0xff),
356 (sa
->_S6_un
._S6_u8
[6]<<8)|(sa
->_S6_un
._S6_u8
[7]&0xff),
357 (sa
->_S6_un
._S6_u8
[8]<<8)|(sa
->_S6_un
._S6_u8
[9]&0xff),
358 (sa
->_S6_un
._S6_u8
[10]<<8)|(sa
->_S6_un
._S6_u8
[11]&0xff),
359 (sa
->_S6_un
._S6_u8
[12]<<8)|(sa
->_S6_un
._S6_u8
[13]&0xff),
360 (sa
->_S6_un
._S6_u8
[14]<<8)|(sa
->_S6_un
._S6_u8
[15]&0xff)
361 #elif HAVE_IP6_SOCKADDR==5
362 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[0]),
363 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[1]),
364 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[2]),
365 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[3]),
366 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[4]),
367 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[5]),
368 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[6]),
369 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[7])
372 Warn("sockaddr_inet6_info(): buffer too short");
379 /* returns information that can be used for constructing an environment
380 variable describing the socket address.
381 if idx is 0, this function writes "ADDR" into namebuff and the IP address
382 into valuebuff, and returns 1 (which means that one more info is there).
383 if idx is 1, it writes "PORT" into namebuff and the port number into
384 valuebuff, and returns 0 (no more info)
385 namelen and valuelen contain the max. allowed length of output chars in the
387 on error this function returns -1.
390 xiosetsockaddrenv_ip6(int idx
, char *namebuff
, size_t namelen
,
391 char *valuebuff
, size_t valuelen
,
392 struct sockaddr_in6
*sa
, int ipproto
) {
395 strcpy(namebuff
, "ADDR");
396 snprintf(valuebuff
, valuelen
, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
397 (sa
->sin6_addr
.s6_addr
[0]<<8)+
398 sa
->sin6_addr
.s6_addr
[1],
399 (sa
->sin6_addr
.s6_addr
[2]<<8)+
400 sa
->sin6_addr
.s6_addr
[3],
401 (sa
->sin6_addr
.s6_addr
[4]<<8)+
402 sa
->sin6_addr
.s6_addr
[5],
403 (sa
->sin6_addr
.s6_addr
[6]<<8)+
404 sa
->sin6_addr
.s6_addr
[7],
405 (sa
->sin6_addr
.s6_addr
[8]<<8)+
406 sa
->sin6_addr
.s6_addr
[9],
407 (sa
->sin6_addr
.s6_addr
[10]<<8)+
408 sa
->sin6_addr
.s6_addr
[11],
409 (sa
->sin6_addr
.s6_addr
[12]<<8)+
410 sa
->sin6_addr
.s6_addr
[13],
411 (sa
->sin6_addr
.s6_addr
[14]<<8)+
412 sa
->sin6_addr
.s6_addr
[15]);
419 return 1; /* there is port information to also be retrieved */
421 return 0; /* no port info coming */
424 strcpy(namebuff
, "PORT");
425 snprintf(valuebuff
, valuelen
, "%u", ntohs(sa
->sin6_port
));
431 #endif /* WITH_IP6 */