Check which getprotobynumber_r() variant to use
[socat.git] / xio-ip6.c
blob8754198cf0a2a54535205cac50ee18af2f183f38
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"
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_INT, 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_PASTSOCKET, 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_INT, 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_INT, 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_INT, 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_INT, 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_INT, 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_INT, 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_INT, 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_INT, 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_INT, 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_INT, 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_INT, 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_INT, 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_INT, 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_INT, 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_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVPATHMTU };
76 #endif
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);
85 if (src[0] == '[') {
86 char plainaddr[INET6_ADDRSTRLEN];
87 char *clos;
89 strncpy(plainaddr, src+1, INET6_ADDRSTRLEN);
90 plainaddr[INET6_ADDRSTRLEN-1] = '\0';
91 if ((clos = strchr(plainaddr, ']')) != NULL)
92 *clos = '\0';
93 return xioip6_pton(plainaddr, dst);
95 if (xiogetaddrinfo(src, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen,
96 0, 0)
97 != STAT_OK) {
98 return STAT_NORETRY;
100 *dst = sockaddr.ip6.sin6_addr;
101 return STAT_OK;
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 */
108 char *endptr;
109 char *baseaddr;
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 '/'",
118 rangename);
119 return STAT_NORETRY;
121 delimind = delimpos - rangename;
122 if (rangename[0] != '[' || rangename[delimind-1] != ']') {
123 Error1("missing brackets for IPv6 range definition \"%s\"",
124 rangename);
125 return STAT_NORETRY;
128 if ((baseaddr = strndup(rangename+1,delimind-2)) == NULL) {
129 Error1("strdup(\"%s\"): out of memory", rangename+1);
130 return STAT_NORETRY;
132 baseaddr[delimind-2] = '\0';
133 if (xiogetaddrinfo(baseaddr, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen,
134 0, 0)
135 != STAT_OK) {
136 return STAT_NORETRY;
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);
148 bits = 128;
151 /* I am starting to dislike C...uint32_t << 32 is undefined... */
152 if (bits == 0) {
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;
172 } else {
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));
178 return 0;
181 int xiorange_ip6andmask(struct xiorange *range) {
182 int i;
183 #if 0
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];
188 #else
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];
193 #endif
194 return 0;
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;
201 int i;
202 char peername[256];
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);
232 return -1;
234 return 0;
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 */
255 char scratch2[32];
256 size_t msglen;
258 *num = 1; /* good for most message types */
259 msglen = cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg);
260 envbuff[0] = '\0';
261 switch (cmsg->cmsg_type) {
262 #if defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO
263 case IPV6_PKTINFO: {
264 struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
265 *num = 2;
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));
273 return STAT_OK;
274 #endif /* defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO */
275 #ifdef IPV6_HOPLIMIT
276 case IPV6_HOPLIMIT:
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);
283 return STAT_OK;
284 #endif /* defined(IPV6_HOPLIMIT) */
285 #ifdef IPV6_RTHDR
286 case IPV6_RTHDR:
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);
290 return STAT_OK;
291 #endif /* defined(IPV6_RTHDR) */
292 #ifdef IPV6_AUTHHDR
293 case IPV6_AUTHHDR:
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);
297 return STAT_OK;
298 #endif
299 #ifdef IPV6_DSTOPTS
300 case IPV6_DSTOPTS:
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);
304 return STAT_OK;
305 #endif /* defined(IPV6_DSTOPTS) */
306 #ifdef IPV6_HOPOPTS
307 case IPV6_HOPOPTS:
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);
311 return STAT_OK;
312 #endif /* defined(IPV6_HOPOPTS) */
313 #ifdef IPV6_FLOWINFO
314 case IPV6_FLOWINFO:
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);
318 return STAT_OK;
319 #endif
320 #ifdef IPV6_TCLASS
321 case IPV6_TCLASS: {
322 unsigned int u;
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);
327 return STAT_OK;
329 #endif
330 default:
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);
334 return STAT_OK;
336 return STAT_OK;
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])
399 #endif
400 ) >= blen) {
401 Warn("sockaddr_inet6_info(): buffer too short");
402 buff[blen-1] = '\0';
404 return buff;
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
415 respective buffer.
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) {
422 switch (idx) {
423 case 0:
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]);
442 switch (ipproto) {
443 case IPPROTO_TCP:
444 case IPPROTO_UDP:
445 #ifdef IPPROTO_SCTP
446 case IPPROTO_SCTP:
447 #endif
448 return 1; /* there is port information to also be retrieved */
449 default:
450 return 0; /* no port info coming */
452 case 1:
453 strcpy(namebuff, "PORT");
454 snprintf(valuebuff, valuelen, "%u", ntohs(sa->sin6_port));
455 return 0;
457 return -1;
460 #endif /* WITH_IP6 */