1 /* 6bed4/router.c -- traffic forwarding daemon for public TSP service
3 * This is an implementation of the profile that makes TSP service publicly
4 * usable, that is without authentication. However to avoid abuse of such
5 * a service, it is not anonymous -- IPv6 addresses contain the IPv4 address
8 * This is an implementation of neighbour and router discovery over a
9 * tunnel that packs IPv6 inside UDP/IPv4. This tunnel mechanism is
10 * targeted specifically at embedded devices that are to function on
11 * any network, including IPv4-only, while being designed as IPv6-only
12 * devices with a fallback to this tunnel.
14 * Interestingly, as a side-effect of this design the router daemon can be
15 * stateless. Any further requirements that are stateful are most likely
16 * filtering, and that can be solved in stateful firewall configuration.
18 * The intention of TSP is to enable IPv4-only hosts to connecto to
19 * IPv6 services; the public TSP profile adds to that the ability to
20 * do it in a temporary manner.
22 * TODO: Should we translate ICMPv4 --> ICMPv6?
24 * From: Rick van Rein <rick@openfortress.nl>
40 #include <sys/types.h>
41 #include <sys/socket.h>
43 #include <sys/select.h>
44 #include <sys/ioctl.h>
46 #include <netinet/in.h>
47 #include <netinet/ip.h>
48 #include <netinet/ip6.h>
49 #include <netinet/tcp.h>
50 #include <netinet/udp.h>
51 #include <netinet/icmp6.h>
52 #include <arpa/inet.h>
55 #include <linux/if_tun.h>
56 #include <linux/if_ether.h>
59 /* The following will initially fail, due to an IANA obligation to avoid
60 * default builds with non-standard options.
68 #ifndef MAX_ROUTABLE_PREFIXES
69 #define MAX_ROUTABLE_PREFIXES 10
74 * The HAVE_SETUP_TUNNEL variable is used to determine whether absense of
75 * the -d option leads to an error, or to an attempt to setup the tunnel.
76 * The setup_tunnel() function used for that is defined per platform, such
77 * as for LINUX. Remember to maintain the manpage's optionality for -d.
79 #undef HAVE_SETUP_TUNNEL
82 /* Global variables */
84 /* SCTP structures are far from standardised, so we define our own header */
86 uint16_t source, dest;
96 char *v4server = NULL;
97 char *v6server = NULL;
98 char *v6prefix = NULL;
100 const uint8_t v6listen_linklocal [16] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
101 uint8_t v6listen_linklocal_complete [16] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
103 uint8_t lladdr_6bed4 [6];
105 struct sockaddr_in6 v6name;
106 struct sockaddr_in v4name;
107 struct sockaddr_in v4name_xlate;
109 struct in6_addr v6listen;
110 struct in6_addr v6listen_complete;
111 struct in_addr v4listen;
113 struct in6_addr v6routable_prefix [MAX_ROUTABLE_PREFIXES];
114 uint8_t v6routable_prefixlen [MAX_ROUTABLE_PREFIXES];
115 int v6routable_prefixcount = 0;
122 struct ip6_hdr v6hdr;
123 uint8_t data [MTU - sizeof (struct ip6_hdr)];
126 struct ip6_hdr v6hdr;
128 struct icmp6_hdr v6icmphdr;
129 struct my_sctphdr v6sctphdr;
130 struct tcphdr v6tcphdr ;
131 struct udphdr v6udphdr ;
133 struct udphdr v6udphdr;
134 struct my_sctphdr v6sctphdr;
141 #define v4tunpi6 ( v4data6.tun)
142 #define v4data ((uint8_t *) &v4data6.udata)
143 #define v4hdr6 (&v4data6.udata.idata.v6hdr)
144 #define v4src6 (&v4data6.udata.idata.v6hdr.ip6_src)
145 #define v4dst6 (&v4data6.udata.idata.v6hdr.ip6_dst)
147 #define v4v6payload ((uint16_t *) &v4data6.udata.ndata.adata)
148 #define v4v6plen ( v4data6.udata.ndata.v6hdr.ip6_plen)
149 #define v4v6nexthdr ( v4data6.udata.ndata.v6hdr.ip6_nxt)
150 #define v4v6hoplimit ( v4data6.udata.ndata.v6hdr.ip6_hops)
152 #define v4v6icmpdata ( v4data6.udata.ndata.adata.v6icmphdr.icmp6_data8)
153 #define v4v6icmptype ( v4data6.udata.ndata.adata.v6icmphdr.icmp6_type)
154 #define v4v6icmpcode ( v4data6.udata.ndata.adata.v6icmphdr.icmp6_code)
155 #define v4v6icmpcksum ( v4data6.udata.ndata.adata.v6icmphdr.icmp6_cksum)
157 #define v4v6sctpofs (offsetof (struct v4frame,adata.v6sctphdr))
158 #define v4v6sctpsrcport ( v4data6.udata.ndata.adata.v6sctphdr.source)
159 #define v4v6sctpdstport ( v4data6.udata.ndata.adata.v6sctphdr.dest)
160 #define v4v6sctpcksum ( v4data6.udata.ndata.adata.v6sctphdr.cksum)
162 #define v4v6tunsctpofs (offsetof (struct v4frame,adata.tdata.v6sctphdr))
163 #define v4v6tunsctpsrcport ( v4data6.udata.ndata.adata.tdata.v6sctphdr.source)
164 #define v4v6tunsctpdstport ( v4data6.udata.ndata.adata.tdata.v6sctphdr.dest)
165 #define v4v6tunsctpcksum ( v4data6.udata.ndata.adata.tdata.v6sctphdr.cksum)
167 #define v4v6tcpsrcport ( v4data6.udata.ndata.adata.v6tcphdr.source)
168 #define v4v6tcpdstport ( v4data6.udata.ndata.adata.v6tcphdr.dest)
169 #define v4v6tcpcksum ( v4data6.udata.ndata.adata.v6tcphdr.check)
171 #define v4v6udpsrcport ( v4data6.udata.ndata.adata.v6udphdr.source)
172 #define v4v6udpdstport ( v4data6.udata.ndata.adata.v6udphdr.dest)
173 #define v4v6udpcksum ( v4data6.udata.ndata.adata.v6udphdr.check)
175 #define v4ngbsoltarget (&v4data6.udata.ndata.adata.v6icmphdr.icmp6_data8 [4])
183 struct ip6_hdr v6hdr;
185 struct icmp6_hdr v6icmphdr;
186 struct my_sctphdr v6sctphdr;
187 struct tcphdr v6tcphdr ;
188 struct udphdr v6udphdr ;
190 struct udphdr v6udphdr;
191 struct my_sctphdr v6sctphdr;
199 #define v6tuncmd ( v6data6.tun)
200 #define v6data ( v6data6.udata.data)
201 #define v6hdr6 (&v6data6.udata.ndata.v6hdr)
202 #define v6src6 (&v6data6.udata.ndata.v6hdr.ip6_src)
203 #define v6dst6 (&v6data6.udata.ndata.v6hdr.ip6_dst)
204 #define v6hoplimit ( v6data6.udata.ndata.v6hdr.ip6_hops)
205 #define v6nexthdr ( v6data6.udata.ndata.v6hdr.ip6_nxt)
207 #define v6icmptype ( v6data6.udata.ndata.adata.v6icmphdr.icmp6_type)
208 #define v6icmpcksum ( v6data6.udata.ndata.adata.v6icmphdr.icmp6_cksum)
210 #define v6sctpcksum ( v6data6.udata.ndata.adata.v6sctphdr.cksum)
211 #define v6tunsctpcksum ( v6data6.udata.ndata.adata.tdata.v6sctphdr.cksum)
213 #define v6sctpofs (offsetof(struct v6frame,adata.v6sctphdr))
214 #define v6tunsctpofs (offsetof(struct v6frame,adata.tdata.v6sctphdr))
216 #define v6tcpcksum ( v6data6.udata.ndata.adata.v6tcphdr.check)
218 #define v6udpcksum ( v6data6.udata.ndata.adata.v6udphdr.check)
219 #define v6udpdstport ( v6data6.udata.ndata.adata.v6udphdr.dest)
220 #define v6udpsrcport ( v6data6.udata.ndata.adata.v6udphdr.source)
223 uint8_t router_linklocal_address [] = {
224 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00,
227 uint8_t democlient_linklocal_address [] = {
228 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01,
231 uint8_t allnodes_linklocal_address [] = {
232 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01,
235 uint8_t allrouters_linklocal_address [] = {
236 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x02,
241 #ifndef MAXNUM_MASQHOST
242 #define MAXNUM_MASQHOST 4
245 uint16_t num_masqhost = 0;
246 uint8_t masqhost [MAXNUM_MASQHOST][16];
248 // ports for 's', 't', 'u' -- SCTP, TCP, UDP have increasing numbers
250 #ifndef MAXNUM_PORTPAIRS
251 #define MAXNUM_PORTPAIRS 10
254 // masqportpairs holds triples <lowport,highport,masqhostnr>
255 uint16_t num_masqportpairs [3] = { 0, 0, 0 };
256 uint16_t masqportpairs [3][3*MAXNUM_PORTPAIRS];
259 uint16_t icmp_num_portpairs = 0;
260 uint16_t icmp_portpairs [3] = { 1, 1, 0 };
270 #ifndef INTERFACE_NAME_6BED4
271 #define INTERFACE_NAME_6BED4 "6bed4"
275 #define HAVE_SETUP_TUNNEL
276 /* Implement the setup_tunnel() command for Linux.
277 * Return 1 on success, 0 on failure.
279 int setup_tunnel (void) {
280 v6sox = open ("/dev/net/tun", O_RDWR);
282 fprintf (stderr, "%s: Failed to access tunnel driver on /dev/net/tun: %s\n", program, strerror (errno));
287 memset (&ifreq, 0, sizeof (ifreq));
288 strncpy (ifreq.ifr_name, INTERFACE_NAME_6BED4, IFNAMSIZ);
289 ifreq.ifr_flags = IFF_TUN;
290 if (ok && (ioctl (v6sox, TUNSETIFF, (void *) &ifreq) == -1)) {
293 ifreq.ifr_name [IFNAMSIZ] = 0;
295 snprintf (cmd, 512, "/sbin/ip -6 addr flush dev %s", ifreq.ifr_name);
296 if (ok && system (cmd) != 0) {
299 snprintf (cmd, 512, "/sbin/ip addr add fe80::0 dev %s scope link", ifreq.ifr_name);
300 if (ok && system (cmd) != 0) {
303 snprintf (cmd, 512, "/sbin/ip -6 addr add %s dev %s", v6prefix, ifreq.ifr_name);
304 if (ok && system (cmd) != 0) {
307 snprintf (cmd, 512, "/sbin/ip link set %s up mtu 1280", ifreq.ifr_name);
308 if (ok && system (cmd) != 0) {
312 close (v6sox); /* This removes the tunnel interface */
313 fprintf (stderr, "Failed to setup tunnel \"%s\"\n", INTERFACE_NAME_6BED4);
327 /* Produce an IPv6 address following the 6bed4 structures.
328 * - The top half is taken from v6listen
329 * - The bottom contains IPv4 address and port from v4name
330 * - The last 14 bits are filled with the lanip parameter
332 void addr_6bed4 (struct in6_addr *dst_ip6, uint16_t lanip) {
333 memcpy (&dst_ip6->s6_addr [0], &v6listen, 8);
334 dst_ip6->s6_addr32 [2] = v4name.sin_addr.s_addr;
335 dst_ip6->s6_addr16 [6] = v4name.sin_port;
336 dst_ip6->s6_addr [14] = ((dst_ip6->s6_addr [8] & 0x03) << 6)
337 | ((lanip >> 8) & 0x3f);
338 dst_ip6->s6_addr [15] = (lanip & 0xff);
339 dst_ip6->s6_addr [8] &= 0xfc;
342 /* Calculate the ICMPv6 checksum field
344 uint16_t icmp6_checksum (struct in6_addr *src6, struct in6_addr *dst6,
345 uint16_t *payload, size_t payloadlen) {
346 uint16_t plenword = htons (payloadlen); // our ICMPv6 is small
347 uint16_t nxthword = htons (IPPROTO_ICMPV6);
348 uint16_t *area [] = { src6->s6_addr16, dst6->s6_addr16,
349 &plenword, &nxthword,
350 payload, &payload [2] };
351 uint8_t areawords [] = { 8, 8, 1, 1, 1, (payloadlen >> 1) - 2 };
354 for (i=0; i < 6; i++) {
355 for (j=0; j<areawords [i]; j++) {
356 csum += ntohs (area [i] [j]);
359 csum = (csum & 0xffff) + (csum >> 16);
360 csum = (csum & 0xffff) + (csum >> 16);
361 csum = htons (~csum);
366 /* Mangle a packet by replacing an IPv6 address, correcting the checksum.
367 * In all of ICMPv6, UDPv6, TCPv6, SCTPv6, the checksumming is a 1's cpl
368 * of a sum of 16-bit words; the position of the words don't matter and
369 * we can subtract the old address' words and add the new address' words.
370 * Or, as a result of the one's complement, the opposite. There is some
371 * inclusion of the top half of a 32-bit sum, but that is also neutral.
373 void masquerade_address (struct in6_addr *var,
374 const struct in6_addr *new,
375 uint16_t *csum_field) {
376 int32_t csum = ntohs (~*csum_field);
378 for (i=0; i<8; i++) {
379 csum -= ntohs (var->s6_addr16 [i]);
380 var->s6_addr16 [i] = new->s6_addr16 [i];
381 csum += ntohs (var->s6_addr16 [i]);
383 csum = (csum & 0xffff) + (csum >> 16);
384 csum = (csum & 0xffff) + (csum >> 16);
385 *csum_field = htons (~csum);
389 /* Send an ICMPv6 reply. This is constructed at the tunnel end, from
390 * the incoming message. The parameter indicates how many bytes the
391 * ICMPv6 package counts after the ICMPv6 header. It must be 4 (mod 8).
393 * Actions: v4/udp src becomes dest, set v4/udp/v6 src, len, cksum, send.
394 * reply is always to v4src6, except that if it starts with
395 * 0x00,0x00 it will be replaced with allnodes_linklocal_address.
397 void icmp6_reply (size_t icmp6bodylen) {
399 if ((icmp6bodylen & 0x07) != 4) {
400 return; /* illegal length, drop */
402 v4v6plen = htons (icmp6bodylen + 4);
404 (v4src6->s6_addr16 [0])
406 : allnodes_linklocal_address,
408 memcpy (v4src6, router_linklocal_address, 16);
409 v4v6icmpcksum = icmp6_checksum (v4src6, v4dst6,
410 v4v6payload, ntohs (v4v6plen));
412 // Send the message to the IPv4 originator port
413 printf ("Sending ICMPv6-IPv6-UDP-IPv4 to %d.%d.%d.%d:%d, result = %zd\n",
414 ((uint8_t *) &v4name.sin_addr.s_addr) [0],
415 ((uint8_t *) &v4name.sin_addr.s_addr) [1],
416 ((uint8_t *) &v4name.sin_addr.s_addr) [2],
417 ((uint8_t *) &v4name.sin_addr.s_addr) [3],
418 ntohs (v4name.sin_port),
421 sizeof (struct ip6_hdr) + 4 + icmp6bodylen,
423 (struct sockaddr *) &v4name, sizeof (v4name)));
427 /* Append the current prefix to an ICMPv6 message. Incoming optidx
428 * and return values signify original and new offset for ICMPv6 options.
429 * The endlife parameter must be set to obtain zero lifetimes, thus
430 * instructing the tunnel client to stop using an invalid prefix.
432 size_t icmp6_prefix_local (size_t optidx, uint8_t endlife) {
433 v4v6icmpdata [optidx++] = 3; // Type
434 v4v6icmpdata [optidx++] = 4; // Length
435 v4v6icmpdata [optidx++] = 114; // This is a /114 prefix
436 v4v6icmpdata [optidx++] = 0xc0; // L=1, A=1, Reserved1=0
437 memset (v4v6icmpdata + optidx, endlife? 0x00: 0xff, 8);
439 // Valid Lifetime: Zero / Infinite
440 // Preferred Lifetime: Zero / Infinite
441 memset (v4v6icmpdata + optidx, 0, 4);
444 addr_6bed4 ((struct in6_addr *) (v4v6icmpdata + optidx), 0);
451 /* Append an extra routed prefix to an ICMPv6 message. Incoming optidx
452 * and return values signify original and new offset for ICMPv6 options.
453 * The endlife parameter must be set to obtain zero lifetimes, thus
454 * instructing the tunnel client to stop using an invalid prefix.
456 size_t icmp6_prefix_routed (size_t optidx, uint8_t endlife, struct in6_addr *prefix, uint8_t prefix_len) {
457 v4v6icmpdata [optidx++] = 3; // Type
458 v4v6icmpdata [optidx++] = 4; // Length
459 v4v6icmpdata [optidx++] = prefix_len;
461 v4v6icmpdata [optidx++] = 0x00; // L=0, A=0, Reserved1=0
462 memset (v4v6icmpdata + optidx, endlife? 0x00: 0xff, 8);
464 // Valid Lifetime: Zero / Infinite
465 // Preferred Lifetime: Zero / Infinite
466 memset (v4v6icmpdata + optidx, 0, 4);
469 memcpy (v4v6icmpdata + optidx, prefix, 16);
479 * Append a Destination Link-Layer Address Option to an ICMPv6
480 * message. The address is comprised from the remote's UDP port
481 * and IPv4 address, as seen by the router. They are supplied
482 * in that order, in network byte order. The resulting address
483 * is 6 bytes, but even though that makes it look like a MAC
484 * address, it really is another beast.
485 * Note that no effort is made in the router to recognise the
486 * "illegal port number" 0x3333 -- the client needs a message
487 * and will recognise it and act on it.
489 size_t icmp6_dest_linkaddr (size_t optidx) {
490 uint8_t typelen [2] = { ND_OPT_DESTINATION_LINKADDR, 1 };
491 memcpy (v4v6icmpdata + optidx + 0, &typelen, 2);
492 v4v6icmpdata [optidx + 2] = ntohs (v4name.sin_port) & 0xff;
493 v4v6icmpdata [optidx + 3] = ntohs (v4name.sin_port) >> 8;
494 memcpy (v4v6icmpdata + optidx + 4, &v4name.sin_addr, 4);
501 * Test if an address is a local override. This function is compiled-in
502 * to support hosts with a /64 from their own ISP and nothing more; they
503 * need to access local IPv6 addresses. We rely on the 6bed4 port being
504 * 0 to decide that an address cannot be anything but a local override.
505 * Define LOCAL_OVERRIDES_PORT0 to enable this feature.
507 #ifdef LOCAL_OVERRIDES_PORT0
508 static inline bool is_local_override (struct in6_addr *ip6) {
509 return (ip6->s6_addr16 [6] == 0) && (memcmp (ip6->s6_addr, &v6listen, 8) == 0);
512 #define is_local_override(_) false
517 * Test if the provided IPv6 address matches the prefix used for 6bed4.
518 *TODO: This is oversimplistic, it only cares for the Hetzner /64
520 static inline bool is_6bed4 (struct in6_addr *ip6) {
521 return memcmp (&v6listen, ip6->s6_addr, 8) == 0;
524 /* Test if the provided IPv6 address matches the fc64::/16 prefix.
525 * If so, the traffic may be bounced using 6bed4 traffic, but it
526 * must not be relayed to the native IPv6 side.
527 * TODO: Perhaps allow only configured <netid>, so fc64:<netid>::/32
529 static inline bool is_fc64 (struct in6_addr *ip6) {
530 return ip6->s6_addr16 [0] == htons (0xfc64);
533 /* Test if the src and destination share the same /114 and the destination
534 * fills up the rest with zero bits; in other words, test that this is a
535 * package targeted from a 6bed4peer node to its 6bed4router. This is used
536 * to distinguish special ICMPv6 messages, as well as masquerading targets.
538 static inline bool is_mine (struct in6_addr *src6, struct in6_addr *dst6) {
539 return ((dst6->s6_addr [15] == 0x00)
540 && ((dst6->s6_addr [14] & 0x3f) == 0x00)
541 && (memcmp (dst6->s6_addr, src6->s6_addr, 14) == 0));
546 * Validate the originator's IPv6 address. It should match the
547 * UDP/IPv4 coordinates of the receiving 6bed4 socket. Also,
548 * the /64 prefix (but not the /114 prefix!) must match v6listen.
550 bool validate_originator (struct in6_addr *ip6) {
553 // Require non-local top halves to match our v6listen_linklocal address
554 // We will enforce our own fallback address (and fc64:<netid>::/32)
555 if (memcmp (ip6, v6listen_linklocal, 8) != 0) {
556 if (memcmp (&v6listen, ip6->s6_addr, 8) != 0) {
561 // Require the sender port to appear in its IPv6 address
562 if (v4name.sin_port != ip6->s6_addr16 [6]) {
566 // Require the sender address to appear in its IPv6 address
567 addr = ntohl (ip6->s6_addr32 [2]) & 0xfcffffff;
568 addr |= ((uint32_t) (ip6->s6_addr [14] & 0xc0)) << (24-6);
569 if (addr != ntohl (v4name.sin_addr.s_addr)) {
573 // We passed with flying colours
580 * Major packet processing functions
585 * Respond to a Router Solicitation received over the 6bed4 Network.
587 void handle_6bed4_router_solicit (void) {
588 struct in6_addr observed;
589 v4v6icmptype = ND_ROUTER_ADVERT;
590 v4v6icmpdata [0] = 0; // Cur Hop Limit: unspec
591 v4v6icmpdata [1] = 0x18; // M=0, O=0
594 // TODO: wire says 0x44 for router_adv.flags
596 memset (v4v6icmpdata+writepos, 0xff, 2+4+4);
597 // Router Lifetime: max, 18.2h
598 // Reachable Time: max
599 // Retrans Timer: max
601 writepos = icmp6_prefix_local (writepos, 0);
602 for (int i = 0; i < v6routable_prefixcount ; i++) {
603 writepos = icmp6_prefix_routed (writepos, 0,
604 &v6routable_prefix [i],
605 v6routable_prefixlen [i]);
607 icmp6_reply (writepos);
611 /* Handle the IPv4 message pointed at by msg as a neighbouring command.
613 * Type Code ICMPv6 meaning Handling
614 * ---- ---- ----------------------------- ----------------------------
615 * 133 0 Router Solicitation Send Router Advertisement
616 * 134 0 Router Advertisement Ignore
617 * 135 0 Neighbour Solicitation Send Neighbour Advertisement
618 * 136 0 Neighbour Advertisement Ignore
619 * 137 0 Redirect Ignore
621 void handle_4to6_nd (ssize_t v4ngbcmdlen) {
622 uint16_t srclinklayer;
623 if (v4ngbcmdlen < sizeof (struct ip6_hdr) + sizeof (struct icmp6_hdr)) {
626 if (v4v6icmpcode != 0) {
629 if (icmp6_checksum (v4src6, v4dst6,
630 v4v6payload, v4ngbcmdlen-sizeof (struct ip6_hdr)
631 ) != v4v6icmpcksum) {
635 // Approved. Perform neighbourly courtesy.
636 switch (v4v6icmptype) {
637 case ND_ROUTER_SOLICIT:
639 // Validate Router Solicitation
641 if (v4ngbcmdlen == sizeof (struct ip6_hdr) + 8 + 8) {
642 // One option is possible, the source link-layer address
643 if (v4v6icmpdata [4] != 1 || v4v6icmpdata [5] != 1) {
644 break; /* bad opton, ignore */
646 // The source link-layer address is end-aligned
647 srclinklayer = (v4v6icmpdata [10] << 8) | v4v6icmpdata [11];
648 if (srclinklayer == 0) {
649 break; /* illegal, ignore */
651 } else if (v4ngbcmdlen == sizeof (struct ip6_hdr) + 8) {
652 srclinklayer = 0; /* set for latter filling */
654 break; /* illegal length, drop */
657 // Having accepted the Router Advertisement, respond
658 handle_6bed4_router_solicit ();
660 case ND_NEIGHBOR_SOLICIT:
662 // Validate Neigbour Solicitation
663 if (!validate_originator (v4src6)) {
664 break; /* bad source address, drop */
666 if ((v4ngbcmdlen != sizeof (struct ip6_hdr) + 24) &&
667 (v4ngbcmdlen != sizeof (struct ip6_hdr) + 24 + 8)) {
668 break; /* funny length, drop */
670 if ((memcmp (v4ngbsoltarget, v6listen_linklocal, 16) != 0) &&
671 (memcmp (v4ngbsoltarget, v6listen_linklocal_complete, 16) != 0) &&
672 (memcmp (v4ngbsoltarget, &v6listen_complete, 16) != 0)) {
673 break; /* target not known here, drop */
676 // Construct Neigbour Advertisement
677 v4v6icmptype = ND_NEIGHBOR_ADVERT;
678 v4v6icmpdata [0] = 0xc0;
681 v4v6icmpdata [3] = 0x00; // R=1, S=1, O=1, Reserved=0
682 memcpy (v4v6icmpdata + 4, &v6listen_complete, 16);
683 // Append option: the target link-layer address
684 // Note: wire does not include target link-layer address
685 v4v6icmpdata [20] = 2; // Type: Target Link-Layer Addr
686 v4v6icmpdata [21] = 1; // Length: 1x 8 bytes
687 memcpy (v4v6icmpdata + 22, lladdr_6bed4, 6);
688 icmp6_reply (28); // 28 is the ICMPv6 response length
690 case ND_ROUTER_ADVERT:
691 case ND_NEIGHBOR_ADVERT:
699 * Forward a message to the masquerading target, or drop it. This is done
700 * with non-6bed4 packets that are sent from a 6bed4peer node to its
701 * 6bed4router address; see is_mine() for the definition. The general idea
702 * is that the address that is to be masqueraded can later be reconstructed
703 * from the 6bed4peer's address.
705 void handle_4to6_masquerading (ssize_t v4datalen) {
706 fprintf (stderr, "Traffic to 6bed4router may be fit for masquerading\n");
707 uint16_t *portpairs = NULL;
708 uint16_t numpairs = 0;
710 uint16_t *csum_field = NULL;
711 uint16_t sctp_offset = 0;
713 switch (v4v6nexthdr) {
715 portpairs = masqportpairs [0]; // 's'
716 numpairs = num_masqportpairs [0];
717 port = ntohs (v4v6sctpdstport);
718 csum_field = &skip_csum;
719 sctp_offset = v4v6sctpofs;
722 portpairs = masqportpairs [1]; // 't'
723 numpairs = num_masqportpairs [1];
724 port = ntohs (v4v6tcpdstport);
725 csum_field = &v4v6tcpcksum;
728 portpairs = masqportpairs [2]; // 'u'
729 numpairs = num_masqportpairs [2];
730 port = ntohs (v4v6udpdstport);
731 csum_field = &v4v6udpcksum;
732 if ((port == 9899) && (v4v6udpsrcport == v4v6udpdstport)) {
733 // SCTP tunneled over UDP (keep csum_field)
734 portpairs = masqportpairs [0];
735 numpairs = num_masqportpairs [0];
736 port = ntohs (v4v6tunsctpdstport);
737 sctp_offset = v4v6tunsctpofs;
741 portpairs = icmp_portpairs;
742 numpairs = icmp_num_portpairs;
743 port = icmp_portpairs [0];
744 csum_field = &v4v6icmpcksum;
749 fprintf (stderr, "DEBUG: Looking for masquerading of port %d in %d entries\n", port, numpairs);
750 while (numpairs-- > 0) {
751 if ((port >= portpairs [0]) && (port <= portpairs [1])) {
753 // Replace masqueraded address by 6bed4router's
754 fprintf (stderr, "DEBUG: Passing traffic to masquerading address number %d\n", portpairs [2]);
755 masquerade_address (v4dst6,
756 (struct in6_addr *) masqhost [portpairs [2]],
758 if (sctp_offset > 0) {
759 //TODO// Recompute SCTP's CRC-32 checksum
760 // recompute_sctp_checksum (ip6hdr, sctp_offset, framelen);
761 //BUT: SCTP checksum does not use pseudo IPhdr
762 //SO: Address masquerading goes undetected :-D
765 // Forward immediately, and return from this function
766 printf ("Writing Masqueraded IPv6, result = %zd\n",
767 write (v6sox, &v4data6, sizeof (struct tun_pi) + v4datalen));
773 // Silently skip the offered packet
778 * Forward a message received over the 6bed4 Network over IPv6.
779 * Note that existing checksums will work well, as only the
780 * Hop Limit has been altered, and this is not part of the
781 * checksum calculations.
783 void handle_4to6_plain_unicast (ssize_t v4datalen) {
784 printf ("Writing IPv6, result = %zd\n",
785 write (v6sox, &v4data6, sizeof (struct tun_pi) + v4datalen));
790 * Forward a 6bed4 message to another 6bed4 destination address.
791 * Local address prefixes fc64:<netid>:<ipv4>::/64 are also relayed.
792 * Note that existing checksums will work well, as only the
793 * Hop Limit has been altered, and this is not part of the
794 * checksum calculations.
796 void relay_4to4_plain_unicast (uint8_t* data, ssize_t v4datalen, struct in6_addr *ip6) {
797 v4name.sin_port = htons (ip6->s6_addr [12] << 8 | ip6->s6_addr [13]);
798 uint8_t *addr = (uint8_t *) &v4name.sin_addr.s_addr;
799 addr [0] = (ip6->s6_addr [8] & 0xfc) | ip6->s6_addr [14] >> 6;
800 memcpy (addr + 1, ip6->s6_addr + 9, 3);
801 printf ("Relaying over 6bed4 Network to %d.%d.%d.%d:%d, result = %zd\n",
802 ((uint8_t *) &v4name.sin_addr.s_addr) [0],
803 ((uint8_t *) &v4name.sin_addr.s_addr) [1],
804 ((uint8_t *) &v4name.sin_addr.s_addr) [2],
805 ((uint8_t *) &v4name.sin_addr.s_addr) [3],
806 ntohs (v4name.sin_port),
810 (struct sockaddr *) &v4name, sizeof (v4name)));
814 /* Receive a tunnel package, and route it to either the handler for the
815 * tunnel protocol, or to the handler that checks and then unpacks the
818 void handle_4to6 (void) {
821 socklen_t adrlen = sizeof (v4name);
823 // Receive IPv4 package, which may be tunneled or a tunnel request
824 buflen = recvfrom (v4sox,
827 (struct sockaddr *) &v4name, &adrlen
830 printf ("%s: Error receiving IPv4-side package: %s",
831 program, strerror (errno));
834 if (buflen < sizeof (struct ip6_hdr)) {
837 if ((v4data [0] & 0xf0) != 0x60) {
838 // Not an IPv6 packet
842 // Handle the tunneled IPv6 package (dependent on its class)
843 if ((v4v6nexthdr == IPPROTO_ICMPV6) &&
844 (v4v6icmptype >= 133) && (v4v6icmptype <= 137)) {
846 // Not Plain: Router Adv/Sol, Neighbor Adv/Sol, Redirect
847 if (v4v6hoplimit != 255) {
850 handle_4to6_nd (buflen);
851 } else if (is_mine (v4src6, v4dst6)) {
852 handle_4to6_masquerading (buflen);
853 } else if ((v4dst6->s6_addr [0] != 0xff) && !(v4dst6->s6_addr [8] & 0x01)) {
856 if (is_local_override (v4dst6)) {
857 // Accept 6bed4 clients, but not forged IPv6 senders
858 if (!validate_originator (v4src6)) {
861 handle_4to6_plain_unicast (buflen);
862 } else if (validate_originator (v4src6)) {
863 if (v4v6hoplimit-- <= 1) {
866 if (is_6bed4 (v4dst6) || is_fc64 (v4dst6)) {
867 relay_4to4_plain_unicast (v4data, buflen, v4dst6);
869 handle_4to6_plain_unicast (buflen);
871 } else if (is_6bed4 (v4src6)) {
872 // The sender must not have kept NAT/firewall holes
873 // open and should be instructed about a change in
874 // its 6bed4 Link-Local Address.
875 handle_6bed4_router_solicit ();
880 //OPTIONAL// validate_originator, hoplimit, relay_mcast.
886 /* Receive an IPv6 package, check its address and pickup IPv4 address and
887 * port, then package it as a tunnel message and forward it to IPv4:port.
889 void handle_6to4 (void) {
892 // Receive the IPv6 package and ensure a consistent size
893 size_t rawlen = read (v6sox, &v6data6, sizeof (v6data6));
895 return; /* error reading, drop */
897 if (rawlen < sizeof (struct tun_pi) + sizeof (struct ip6_hdr) + 1) {
898 return; /* too small, drop */
900 if (v6tuncmd.proto != htons (ETH_P_IPV6)) {
901 return; /* no IPv6, drop */
903 if ((v6nexthdr == IPPROTO_ICMPV6) &&
904 (v6icmptype >= 133) && (v6icmptype <= 137)) {
905 return; /* not plain IPv6, drop */
907 if (v6hoplimit-- <= 1) {
908 // TODO: Send back an ICMPv6 error message
909 return; /* hop limit exceeded, drop */
911 if ((v6dst6->s6_addr [0] == 0xff) /* TODO:UDP_PORT_NOT_YET_FORCED_TO_EVEN || (v6dst6->s6_addr [8] & 0x01) */ ) {
912 printf ("Received multicast IPv6 data, flags=0x%04x, proto=0x%04x\n", v6tuncmd.flags, v6tuncmd.proto);
913 //OPTIONAL// handle_6to4_plain_multicast ()
914 return; /* multicast, drop */
916 printf ("Received plain unicast IPv6 data, flags=0x%04x, proto=0x%04x\n", v6tuncmd.flags, v6tuncmd.proto);
918 // Replace masqueraded addresses configured with -m and its default ::1
919 //TODO// Better use the port number to find the find the masqhost
920 for (mqh=0; mqh<num_masqhost; mqh++) {
921 if (memcmp (v6src6, masqhost [mqh], 16) == 0) {
922 printf ("Masqueraded sender address in 6to4 set to the client's 6bed4router address\n");
923 uint16_t *csum_field = NULL;
925 struct in6_addr masq_src;
926 uint16_t sctp_offset = 0;
929 csum_field = &fake_csum;
930 sctp_offset = v6sctpofs;
933 csum_field = &v6tcpcksum;
936 csum_field = &v6udpcksum;
937 if ((v6udpsrcport == v6udpdstport) &&
938 (v6udpsrcport == htons (9899))) {
939 // SCTP tunneled over UDP
940 sctp_offset = v6tunsctpofs;
944 csum_field = &v6icmpcksum;
950 // Construct v6src6 from v6dst6, ending in 14 zero bits
951 memcpy (&masq_src, v6dst6, 16);
952 masq_src.s6_addr16 [7] &= htons (0xc000);
953 fprintf (stderr, "Masquerading cksum.old = 0x%04x, ", ntohs (*csum_field));
954 masquerade_address (v6src6, &masq_src, csum_field);
955 if (sctp_offset > 0) {
956 //TODO// Recompute SCTP's CRC-32 checksum
957 // recompute_sctp_checksum (ip6hdr, sctp_offset, framelen);
958 //BUT: SCTP checksum does not use pseudo IPhdr
959 //SO: Address masquerading goes undetected :-D
961 fprintf (stderr, "cksum.new = 0x%04x\n", ntohs (*csum_field));
966 // Ensure that the incoming IPv6 address is properly formatted
967 // Note that this avoids access to ::1/128, fe80::/10, fec0::/10
968 #ifndef TODO_PERMIT_BOUNCE_FOR_32BIT_PREFIX
969 if (memcmp (v6dst6, &v6listen, 8) != 0) {
973 if (v6dst6->s6_addr32 [0] != v6listen.s6_addr32 [0]) {
974 // Mismatch /32 so this is not going to fly (anywhere)
976 } else if (v6dst6->s6_addr32 [1] != v6listen.s6_addr32 [1]) {
977 // Match /32 but mismatch /64 -- relay to proper fallback
978 // that fc64::/16 is not welcome in 6to4 processing
979 //TODO//OVER_6bed4// relay_6to6_plain_unicast (v6data, rawlen - sizeof (struct tun_pi), v6dst6);
983 // Harvest socket address data from destination IPv6, then send
984 relay_4to4_plain_unicast (v6data, rawlen - sizeof (struct tun_pi), v6dst6);
988 /* Run the daemon core code, passing information between IPv4 and IPv6 and
989 * responding to tunnel requests if so requested.
991 void run_daemon (void) {
996 int nfds = (v4sox < v6sox)? (v6sox + 1): (v4sox + 1);
998 select (nfds, &io, NULL, NULL, NULL);
999 if (FD_ISSET (v4sox, &io)) {
1002 FD_SET (v4sox, &io);
1004 if (FD_ISSET (v6sox, &io)) {
1007 FD_SET (v6sox, &io);
1014 /* Option descriptive data structures */
1016 char *short_opt = "l:L:R:d:hit:u:s:m:x:";
1018 struct option long_opt [] = {
1019 { "v4listen", 1, NULL, 'l' },
1020 { "v6prefix", 1, NULL, 'L' },
1021 { "v6route", 1, NULL, 'R' },
1022 { "tundev", 1, NULL, 'd' },
1023 { "help", 0, NULL, 'h' },
1024 { "icmp", 0, NULL, 'i' },
1025 { "tcp", 1, NULL, 't' },
1026 { "udp", 1, NULL, 'u' },
1027 { "sctp", 1, NULL, 's' },
1028 { "masqhost", 1, NULL, 'm' },
1029 { "xlate", 1, NULL, 'x' },
1030 // { "fallback4", 1 NULL, 'f' },
1031 // { "fallback6", 1, NULL, 'F' },
1032 { NULL, 0, NULL, 0 } /* Array termination */
1035 /* Parse commandline arguments (and start to process them).
1036 * Return 1 on success, 0 on failure.
1038 int process_args (int argc, char *argv []) {
1040 int help = (argc == 1);
1044 switch (opt = getopt_long (argc, argv, short_opt, long_opt, NULL)) {
1047 if (optind != argc) {
1048 fprintf (stderr, "%s: Extra arguments not permitted: %s...\n", program, argv [optind]);
1053 if (v4name.sin_family != 0) {
1055 fprintf (stderr, "%s: Only one -l argument is permitted\n", program);
1058 v4name.sin_family = AF_INET;
1060 if (inet_pton (AF_INET, optarg, &v4name.sin_addr) <= 0) {
1062 fprintf (stderr, "%s: Failed to parse IPv4 address %s\n", program, optarg);
1065 memcpy (&v4listen, &v4name.sin_addr, 4);
1068 if (v4name_xlate.sin_family != 0) {
1070 fprintf (stderr, "%s: At most one -x argument is permitted\n", program);
1073 v4name_xlate.sin_family = AF_INET;
1074 ((uint8_t *) &v4name_xlate.sin_addr.s_addr) [0] = 127;
1075 ((uint8_t *) &v4name_xlate.sin_addr.s_addr) [1] = 0;
1076 ((uint8_t *) &v4name_xlate.sin_addr.s_addr) [2] = 0;
1077 ((uint8_t *) &v4name_xlate.sin_addr.s_addr) [3] = 1;
1078 int port = atoi (optarg);
1079 if ((port <= 0) || (port > 65535)) {
1081 fprintf (stderr, "%s: Port number for -x out of range\n", program);
1084 v4name_xlate.sin_port = htons (port);
1089 fprintf (stderr, "%s: Only one -L argument is permitted\n", program);
1092 char *slash64 = strchr (optarg, '/');
1093 if (!slash64 || strcmp (slash64, "/64") != 0) {
1095 fprintf (stderr, "%s: The -L argument must be an explicit /64 prefix and not %s\n", program, slash64? slash64: "implied");
1099 v6server = strdup (optarg);
1102 if (!v6server || (inet_pton (AF_INET6, v6server, &v6listen) <= 0)) {
1104 fprintf (stderr, "%s: Failed to parse IPv6 prefix %s\n", program, optarg);
1107 if (v6listen.s6_addr32 [2] || v6listen.s6_addr32 [3]) {
1109 fprintf (stderr, "%s: IPv6 prefix contains bits beyond its /64 prefix: %s\n", program, optarg);
1114 if (v6routable_prefixcount >= MAX_ROUTABLE_PREFIXES) {
1116 fprintf (stderr, "%s: You cannot provide more than %d prefixes\n", program, MAX_ROUTABLE_PREFIXES);
1119 char *prefix = strdup (optarg);
1120 char *prefixslash = strchr (prefix, '/');
1121 int prefixlen = atoi (prefixslash + 1);
1122 *prefixslash = '\0';
1123 if ((prefixlen < 16) || (prefixlen > 128)) {
1125 fprintf (stderr, "%s: IPv6 route prefix %s must be /16 up to /128\n", program, prefixslash + 1);
1126 } else if (inet_pton (AF_INET6, prefix, &v6routable_prefix [v6routable_prefixcount]) <= 0) {
1128 fprintf (stderr, "%s: Failed to parse IPv6 route %s", program, optarg);
1130 v6routable_prefixlen [v6routable_prefixcount++] = prefixlen;
1137 fprintf (stderr, "%s: Multiple -d arguments are not permitted\n", program);
1140 v6sox = open (optarg, O_RDWR);
1143 fprintf (stderr, "%s: Failed to open tunnel device %s: %s\n", program, optarg, strerror (errno));
1151 // Masqueraded port (range) for SCTP, TCP, UDP
1152 //TODO// Should we support ICMPv6 as well? [honeypots]
1153 if (num_masqhost == 0) {
1154 //TODO// Reference v6listen instead of ::1
1155 inet_pton (AF_INET6, "::1", masqhost [0]);
1158 // Temporary variables in local scope
1160 if (icmp_num_portpairs > 0) {
1161 fprintf (stderr, "%s: Only one ICMP masquerading setting is possible\n", program);
1165 icmp_portpairs [2] = num_masqhost - 1;
1166 icmp_num_portpairs++;
1168 unsigned long fromport, toport;
1169 uint16_t *portpairs;
1171 if (*optarg != ':') {
1172 fromport = strtoul (optarg, &optarg, 10);
1176 if (*optarg != ':') {
1178 } else if (*++optarg) {
1179 toport = strtoul (optarg, &optarg, 10);
1183 if (errno || *optarg) {
1184 fprintf (stderr, "%s: Failed to parse port or port:port\n", program);
1188 if ((fromport < 1) || (fromport > toport) || (toport > 65535)) {
1189 fprintf (stderr, "%s: Invalid port or port range\n", program);
1193 if (++num_masqportpairs [opt-'s'] >= MAXNUM_PORTPAIRS) {
1194 fprintf (stderr, "%s: You cannot define so many ports / port pairs\n", program);
1198 portpairs = &masqportpairs [opt-'s'][3*(num_masqportpairs [opt-'s']-1)];
1199 portpairs [0] = fromport;
1200 portpairs [1] = toport;
1201 portpairs [2] = num_masqhost-1;
1205 // Masqueraded host for TCP, UDP, SCTP (default is ::1)
1206 if (++num_masqhost >= MAXNUM_MASQHOST) {
1207 fprintf (stderr, "%s: No more than %d masquering hosts can be specified\n", program, MAXNUM_MASQHOST);
1211 if (inet_pton (AF_INET6, optarg, masqhost [num_masqhost]) != 1) {
1212 fprintf (stderr, "%s: Unsupported masquerading host \"%s\"\n", program, optarg);
1220 // // Fallback addresses for IPv4, IPv6
1221 // ok = 0; //TODO:IMPLEMENT//
1226 /* continue into 'h' to produce usage information */
1236 #ifdef HAVE_SETUP_TUNNEL
1237 fprintf (stderr, "Usage: %s [-d /dev/tunX] -l <v4server> [-x <port>] -L <v6prefix>/64 [-R <v6route>/n]...\n %s -h\n", program, program);
1238 fprintf (stderr, "\tUse -s|-t|-u to masquerade a port (range) to last -m host or ::1\n");
1240 fprintf (stderr, "Usage: %s -d /dev/tunX -l <v4server> -L <v6prefix>/64\n %s -h\n", program, program);
1241 fprintf (stderr, "\tUse -s|-t|-u to masquerade a port (range) to last -m host of ::1\n");
1245 if (v4name.sin_family == 0) {
1246 fprintf (stderr, "%s: Use -l to specify an IPv4 address for the tunnel interface\n", program);
1249 if (v4name_xlate.sin_family == 0) {
1250 memcpy (&v4name_xlate, &v4name, sizeof (v4name_xlate));
1252 v4server = "127.0.0.1";
1254 v4sox = socket (AF_INET, SOCK_DGRAM, 0);
1256 fprintf (stderr, "%s: Failed to allocate UDPv4 socket: %s\n", program, strerror (errno));
1259 if (bind (v4sox, (struct sockaddr *) &v4name_xlate, sizeof (v4name_xlate)) != 0) {
1260 fprintf (stderr, "%s: Failed to bind to UDPv4 %s:%d: %s\n", program, v4server, ntohs (v4name_xlate.sin_port), strerror (errno));
1266 #ifdef HAVE_SETUP_TUNNEL
1268 if (geteuid () != 0) {
1269 fprintf (stderr, "%s: You should be root, or use -d to specify an accessible tunnel device\n", program);
1272 ok = setup_tunnel ();
1275 fprintf (stderr, "%s: Use -L to specify a /64 prefix on the IPv6 side\n", program);
1278 #else /* ! HAVE_SETUP_TUNNEL */
1280 fprintf (stderr, "%s: You must specify a tunnel device with -d that is accessible to you\n", program);
1283 #endif /* HAVE_SETUP_TUNNEL */
1288 /* The main program parses commandline arguments and forks off the daemon
1290 int main (int argc, char *argv []) {
1294 memset (&v6name , 0, sizeof (v6name ));
1295 memset (&v4name , 0, sizeof (v4name ));
1296 memset (&v4name_xlate, 0, sizeof (v4name_xlate));
1297 v6name.sin6_family = AF_INET6;
1298 v4name.sin_port = htons (UDP_PORT_6BED4); /* 6BED4 standard port */
1300 v4tunpi6.proto = htons (ETH_P_IPV6);
1302 // Parse commandline arguments
1303 if (!process_args (argc, argv)) {
1307 // Setup a few addresses for later comparison/reproduction
1308 // * lladdr_6bed4 is the 6bed4 Link-Local Address
1309 // * v6listen_complete is the router's full IPv6 address (with if-id)
1310 // * v6listen_linklocal_complete is fe80::/64 plus the router's if-id
1311 // A few others have already been setup at this time
1312 // * v6listen is the router's 6bed4 prefix ending in 64 zero bits
1313 // * v6listen_linklocal is the address fe80::/128
1315 lladdr_6bed4 [0] = UDP_PORT_6BED4 & 0xff;
1316 lladdr_6bed4 [1] = UDP_PORT_6BED4 >> 8;
1317 memcpy (lladdr_6bed4 + 2, (uint8_t *) &v4name.sin_addr, 4);
1318 addr_6bed4 (&v6listen_complete, 0);
1320 memcpy (v6listen_linklocal_complete, v6listen_linklocal, 8);
1321 memcpy (v6listen_linklocal_complete + 8, &v6listen_complete.s6_addr [8], 8);
1322 printf ("LISTEN lladdr_6bed4 = %02x:%02x:%02x:%02x:%02x:%02x\n", lladdr_6bed4 [0], lladdr_6bed4 [1], lladdr_6bed4 [2], lladdr_6bed4 [3], lladdr_6bed4 [4], lladdr_6bed4 [5]);
1323 printf ("LISTEN v6listen = %x:%x:%x:%x:%x:%x:%x:%x\n", htons (v6listen.s6_addr16 [0]), htons (v6listen.s6_addr16 [1]), htons (v6listen.s6_addr16 [2]), htons (v6listen.s6_addr16 [3]), htons (v6listen.s6_addr16 [4]), htons (v6listen.s6_addr16 [5]), htons (v6listen.s6_addr16 [6]), htons (v6listen.s6_addr16 [7]));
1324 printf ("LISTEN v6listen_complete = %x:%x:%x:%x:%x:%x:%x:%x\n", htons (v6listen_complete.s6_addr16 [0]), htons (v6listen_complete.s6_addr16 [1]), htons (v6listen_complete.s6_addr16 [2]), htons (v6listen_complete.s6_addr16 [3]), htons (v6listen_complete.s6_addr16 [4]), htons (v6listen_complete.s6_addr16 [5]), htons (v6listen_complete.s6_addr16 [6]), htons (v6listen_complete.s6_addr16 [7]));
1325 printf ("LISTEN v6listen_linklocal = %x:%x:%x:%x:%x:%x:%x:%x\n", htons (((uint16_t *) v6listen_linklocal) [0]), htons (((uint16_t *) v6listen_linklocal) [1]), htons (((uint16_t *) v6listen_linklocal) [2]), htons (((uint16_t *) v6listen_linklocal) [3]), htons (((uint16_t *) v6listen_linklocal) [4]), htons (((uint16_t *) v6listen_linklocal) [5]), htons (((uint16_t *) v6listen_linklocal) [6]), htons (((uint16_t *) v6listen_linklocal) [7]));
1326 printf ("LISTEN v6listen_linklocal_complete = %x:%x:%x:%x:%x:%x:%x:%x\n", htons (((uint16_t *) v6listen_linklocal_complete) [0]), htons (((uint16_t *) v6listen_linklocal_complete) [1]), htons (((uint16_t *) v6listen_linklocal_complete) [2]), htons (((uint16_t *) v6listen_linklocal_complete) [3]), htons (((uint16_t *) v6listen_linklocal_complete) [4]), htons (((uint16_t *) v6listen_linklocal_complete) [5]), htons (((uint16_t *) v6listen_linklocal_complete) [6]), htons (((uint16_t *) v6listen_linklocal_complete) [7]));
1328 // Start the main daemon process
1329 #ifdef SKIP_TESTING_KLUDGE_IN_FOREGROUND
1331 case -1: /* Error forking */
1332 fprintf (stderr, "%s: Failed to fork: %s\n", program, strerror (errno));
1334 case 0: /* Child process */
1336 //TODO: tmp.support for ^printf// close (1);
1341 default: /* Parent process */
1350 // Report successful creation of the daemon