version 1.7.3.0
[socat.git] / xio-ip6.c
blob2e5c6298b21ca39c7c2e6ae714e4a6a2a1909db5
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"
9 #if WITH_IP6
11 #include "xioopen.h"
12 #include "xio-ascii.h"
13 #include "xio-socket.h"
14 #include "xio-ip.h" /* xiogetaddrinfo() */
16 #include "xio-ip6.h"
19 static char *inet6addr_info(const struct in6_addr *sa, char *buff, size_t blen);
22 #ifdef IPV6_V6ONLY
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 };
24 #endif
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 };
27 #endif
28 #ifdef IPV6_PKTINFO
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 };
30 #endif
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 };
33 #endif
34 #ifdef IPV6_RTHDR
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 };
36 #endif
37 #ifdef IPV6_RECVRTHDR
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 };
39 #endif
40 #ifdef IPV6_AUTHHDR
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 };
42 #endif
43 #ifdef IPV6_DSTOPTS
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 };
45 #endif
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 };
48 #endif
49 #ifdef IPV6_HOPOPTS
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 };
51 #endif
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 };
54 #endif
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 };
57 #endif
58 #ifdef IPV6_HOPLIMIT
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 };
60 #endif
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 };
64 #endif
65 #ifdef IPV6_RECVERR
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 };
67 #endif
68 #ifdef IPV6_TCLASS
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 };
70 #endif
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 };
73 #endif
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 };
76 #endif
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 */
82 char *endptr;
83 char *baseaddr;
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\"",
92 rangename);
93 return STAT_NORETRY;
95 if ((delimpos = strchr(rangename, '/')) == NULL) {
96 Error1("xioparsenetwork_ip6(\"%s\",,): missing mask bits delimiter '/'",
97 rangename);
98 return STAT_NORETRY;
100 delimind = delimpos - rangename;
102 if ((baseaddr = strdup(rangename+1)) == NULL) {
103 Error1("strdup(\"%s\"): out of memory", rangename+1);
104 return STAT_NORETRY;
106 baseaddr[delimind-1] = '\0';
107 if (xiogetaddrinfo(baseaddr, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen,
108 0, 0)
109 != STAT_OK) {
110 return STAT_NORETRY;
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);
122 bits = 128;
125 /* I am starting to dislike C...uint32_t << 32 is undefined... */
126 if (bits == 0) {
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;
146 } else {
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));
152 return 0;
155 int xiorange_ip6andmask(struct xiorange *range) {
156 int i;
157 #if 0
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];
162 #else
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];
167 #endif
168 return 0;
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;
175 int i;
176 char peername[256];
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);
206 return -1;
208 return 0;
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 */
229 char scratch2[32];
230 size_t msglen;
232 *num = 1; /* good for most message types */
233 msglen = cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg);
234 envbuff[0] = '\0';
235 switch (cmsg->cmsg_type) {
236 #if defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO
237 case IPV6_PKTINFO: {
238 struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
239 *num = 2;
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));
247 return STAT_OK;
248 #endif /* defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO */
249 #ifdef IPV6_HOPLIMIT
250 case IPV6_HOPLIMIT:
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);
257 return STAT_OK;
258 #endif /* defined(IPV6_HOPLIMIT) */
259 #ifdef IPV6_RTHDR
260 case IPV6_RTHDR:
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);
264 return STAT_OK;
265 #endif /* defined(IPV6_RTHDR) */
266 #ifdef IPV6_AUTHHDR
267 case IPV6_AUTHHDR:
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);
271 return STAT_OK;
272 #endif
273 #ifdef IPV6_DSTOPTS
274 case IPV6_DSTOPTS:
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);
278 return STAT_OK;
279 #endif /* defined(IPV6_DSTOPTS) */
280 #ifdef IPV6_HOPOPTS
281 case IPV6_HOPOPTS:
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);
285 return STAT_OK;
286 #endif /* defined(IPV6_HOPOPTS) */
287 #ifdef IPV6_FLOWINFO
288 case IPV6_FLOWINFO:
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);
292 return STAT_OK;
293 #endif
294 #ifdef IPV6_TCLASS
295 case IPV6_TCLASS:
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);
299 return STAT_OK;
300 #endif
301 default:
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);
305 return STAT_OK;
307 return STAT_OK;
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])
370 #endif
371 ) >= blen) {
372 Warn("sockaddr_inet6_info(): buffer too short");
373 buff[blen-1] = '\0';
375 return buff;
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
386 respective buffer.
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) {
393 switch (idx) {
394 case 0:
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]);
413 switch (ipproto) {
414 case IPPROTO_TCP:
415 case IPPROTO_UDP:
416 #ifdef IPPROTO_SCTP
417 case IPPROTO_SCTP:
418 #endif
419 return 1; /* there is port information to also be retrieved */
420 default:
421 return 0; /* no port info coming */
423 case 1:
424 strcpy(namebuff, "PORT");
425 snprintf(valuebuff, valuelen, "%u", ntohs(sa->sin6_port));
426 return 0;
428 return -1;
431 #endif /* WITH_IP6 */