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>
39 #include <sys/types.h>
40 #include <sys/socket.h>
42 #include <sys/select.h>
43 #include <sys/ioctl.h>
45 #include <netinet/in.h>
46 #include <netinet/ip.h>
47 #include <netinet/ip6.h>
48 #include <netinet/udp.h>
49 #include <netinet/icmp6.h>
50 #include <arpa/inet.h>
53 #include <linux/if_tun.h>
54 #include <linux/if_ether.h>
57 /* The following will initially fail, due to an IANA obligation to avoid
58 * default builds with non-standard options.
66 * The HAVE_SETUP_TUNNEL variable is used to determine whether absense of
67 * the -t option leads to an error, or to an attempt to setup the tunnel.
68 * The setup_tunnel() function used for that is defined per platform, such
69 * as for LINUX. Remember to maintain the manpage's optionality for -t.
71 #undef HAVE_SETUP_TUNNEL
74 /* Global variables */
81 char *v4server = NULL;
82 char *v6server = NULL;
83 char *v6prefix = NULL;
85 const uint8_t v6listen_linklocal [16] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
86 uint8_t v6listen_linklocal_complete [16] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
88 uint8_t lladdr_6bed4 [6];
90 struct sockaddr_in v4name;
91 struct sockaddr_in6 v6name;
93 struct in6_addr v6listen;
94 struct in6_addr v6listen_complete;
95 struct in_addr v4listen;
102 struct ip6_hdr v6hdr;
103 uint8_t data [MTU - sizeof (struct ip6_hdr)];
106 struct ip6_hdr v6hdr;
107 struct icmp6_hdr v6icmphdr;
112 #define v4tunpi6 ( v4data6.tun)
113 #define v4data ((uint8_t *) &v4data6.udata)
114 #define v4hdr6 (&v4data6.udata.idata.v6hdr)
115 #define v4src6 (&v4data6.udata.idata.v6hdr.ip6_src)
116 #define v4dst6 (&v4data6.udata.idata.v6hdr.ip6_dst)
118 #define v4v6plen ( v4data6.udata.ndata.v6hdr.ip6_plen)
119 #define v4v6nexthdr ( v4data6.udata.ndata.v6hdr.ip6_nxt)
120 #define v4v6hoplimit ( v4data6.udata.ndata.v6hdr.ip6_hops)
122 #define v4icmp6 (&v4data6.udata.ndata.v6icmphdr)
123 #define v4v6icmpdata ( v4data6.udata.ndata.v6icmphdr.icmp6_data8)
124 #define v4v6icmptype ( v4data6.udata.ndata.v6icmphdr.icmp6_type)
125 #define v4v6icmpcode ( v4data6.udata.ndata.v6icmphdr.icmp6_code)
126 #define v4v6icmpcksum ( v4data6.udata.ndata.v6icmphdr.icmp6_cksum)
128 #define v4ngbsoltarget (&v4data6.udata.ndata.v6icmphdr.icmp6_data8 [4])
135 struct ip6_hdr v6hdr;
136 struct icmp6_hdr v6icmp;
141 #define v6tuncmd ( v6data6.tun)
142 #define v6data ( v6data6.udata.data)
143 #define v6hdr6 (&v6data6.udata.v6hdr)
144 #define v6src6 (&v6data6.udata.v6hdr.ip6_src)
145 #define v6dst6 (&v6data6.udata.v6hdr.ip6_dst)
146 #define v6hoplimit ( v6data6.udata.v6hdr.ip6_hops)
148 #define v6nexthdr ( v6data6.udata.v6hdr.ip6_nxt)
149 #define v6icmptype ( v6data6.udata.v6icmp.icmp6_type)
152 uint8_t router_linklocal_address [] = {
153 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00,
156 uint8_t democlient_linklocal_address [] = {
157 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01,
160 uint8_t allnodes_linklocal_address [] = {
161 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01,
164 uint8_t allrouters_linklocal_address [] = {
165 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x02,
168 void addr_6bed4(struct in6_addr *dst_ip6, uint8_t *s_addr, int sin_port, int lanip) {
170 dst_ip6->s6_addr [8] = s_addr [0] & 0xfc;
171 memcpy (&dst_ip6->s6_addr [9], s_addr + 1, 3);
172 dst_ip6->s6_addr [12] = sin_port >> 8;
173 dst_ip6->s6_addr [13] = sin_port & 0xff;
174 dst_ip6->s6_addr [14] = (s_addr [0] & 0x03) << 6 | lanip >> 8;
175 dst_ip6->s6_addr [15] = lanip & 0xff;
185 #define HAVE_SETUP_TUNNEL
186 /* Implement the setup_tunnel() command for Linux.
187 * Return 1 on success, 0 on failure.
189 int setup_tunnel (void) {
190 v6sox = open ("/dev/net/tun", O_RDWR);
192 fprintf (stderr, "%s: Failed to access tunnel driver on /dev/net/tun: %s\n", program, strerror (errno));
197 memset (&ifreq, 0, sizeof (ifreq));
198 strncpy (ifreq.ifr_name, "6bed4", IFNAMSIZ);
199 ifreq.ifr_flags = IFF_TUN;
200 if (ok && (ioctl (v6sox, TUNSETIFF, (void *) &ifreq) == -1)) {
203 ifreq.ifr_name [IFNAMSIZ] = 0;
205 snprintf (cmd, 512, "/sbin/ip -6 addr flush dev %s", ifreq.ifr_name);
206 if (ok && system (cmd) != 0) {
209 snprintf (cmd, 512, "/sbin/ip addr add fe80::0 dev %s scope link", ifreq.ifr_name);
210 if (ok && system (cmd) != 0) {
213 snprintf (cmd, 512, "/sbin/ip -6 addr add %s dev %s", v6prefix, ifreq.ifr_name);
214 if (ok && system (cmd) != 0) {
217 snprintf (cmd, 512, "/sbin/ip link set %s up mtu 1280", ifreq.ifr_name);
218 if (ok && system (cmd) != 0) {
222 close (v6sox); /* This removes the tunnel interface */
236 /* Calculate the ICMPv6 checksum field
238 uint16_t icmp6_checksum (size_t payloadlen) {
239 uint16_t plenword = htons (payloadlen);
240 uint16_t nxthword = htons (IPPROTO_ICMPV6);
241 uint16_t *area [] = { (uint16_t *) v4src6, (uint16_t *) v4dst6, &plenword, &nxthword, (uint16_t *) v4icmp6, (uint16_t *) v4v6icmpdata };
242 uint8_t areawords [] = { 8, 8, 1, 1, 1, payloadlen/2 - 2 };
245 for (i=0; i < 6; i++) {
246 for (j=0; j<areawords [i]; j++) {
247 csum += ntohs (area [i] [j]);
250 csum = (csum & 0xffff) + (csum >> 16);
251 csum = (csum & 0xffff) + (csum >> 16);
252 csum = htons (~csum);
257 /* Send an ICMPv6 reply. This is constructed at the tunnel end, from
258 * the incoming message. The parameter indicates how many bytes the
259 * ICMPv6 package counts after the ICMPv6 header. It must be 4 (mod 8).
261 * Actions: v4/udp src becomes dest, set v4/udp/v6 src, len, cksum, send.
262 * reply is always to v4src6, except that if it starts with
263 * 0x00,0x00 it will be replaced with allnodes_linklocal_address.
265 void icmp6_reply (size_t icmp6bodylen) {
267 if ((icmp6bodylen & 0x07) != 4) {
268 return; /* illegal length, drop */
270 v4v6plen = htons (icmp6bodylen + 4);
272 (v4src6->s6_addr16 [0]) ? v4src6 : allnodes_linklocal_address,
274 memcpy (v4src6, router_linklocal_address, 16);
275 v4v6icmpcksum = icmp6_checksum (ntohs (v4v6plen));
277 // Send the message to the IPv4 originator port
278 printf ("Sending ICMPv6-IPv6-UDP-IPv4 to %d.%d.%d.%d:%d, result = %zd\n",
279 ((uint8_t *) &v4name.sin_addr.s_addr) [0],
280 ((uint8_t *) &v4name.sin_addr.s_addr) [1],
281 ((uint8_t *) &v4name.sin_addr.s_addr) [2],
282 ((uint8_t *) &v4name.sin_addr.s_addr) [3],
283 ntohs (v4name.sin_port),
286 sizeof (struct ip6_hdr) + 4 + icmp6bodylen,
288 (struct sockaddr *) &v4name, sizeof (v4name)));
292 /* Append the current prefix to an ICMPv6 message. Incoming optidx
293 * and return values signify original and new offset for ICMPv6 options.
294 * The endlife parameter must be set to obtain zero lifetimes, thus
295 * instructing the tunnel client to stop using an invalid prefix.
297 size_t icmp6_prefix (size_t optidx, uint8_t endlife) {
298 v4v6icmpdata [optidx++] = 3; // Type
299 v4v6icmpdata [optidx++] = 4; // Length
300 v4v6icmpdata [optidx++] = 64; // This is a /64 prefix
301 v4v6icmpdata [optidx++] = 0xc0; // L=1, A=1, Reserved1=0
302 memset (v4v6icmpdata + optidx, endlife? 0x00: 0xff, 8);
304 // Valid Lifetime: Zero / Infinite
305 // Preferred Lifetime: Zero / Infinite
306 memset (v4v6icmpdata + optidx, 0, 4);
309 memcpy (v4v6icmpdata + optidx + 0, &v6listen, 8);
310 memset (v4v6icmpdata + optidx + 8, 0, 8);
319 * Append a Destination Link-Layer Address Option to an ICMPv6
320 * message. The address is comprised from the remote's UDP port
321 * and IPv4 address, as seen by the router. They are supplied
322 * in that order, in network byte order. The resulting address
323 * is 6 bytes, but even though that makes it look like a MAC
324 * address, it really is another beast.
325 * Note that no effort is made in the router to recognise the
326 * "illegal port number" 0x3333 -- the client needs a message
327 * and will recognise it and act on it.
329 size_t icmp6_dest_linkaddr (size_t optidx) {
330 uint8_t typelen [2] = { ND_OPT_DESTINATION_LINKADDR, 1 };
331 memcpy (v4v6icmpdata + optidx + 0, &typelen, 2);
332 v4v6icmpdata [optidx + 2] = ntohs (v4name.sin_port) & 0xff;
333 v4v6icmpdata [optidx + 3] = ntohs (v4name.sin_port) >> 8;
334 memcpy (v4v6icmpdata + optidx + 4, &v4name.sin_addr, 4);
341 * Test if an address is a local override. This function is compiled-in
342 * to support hosts with a /64 from their own ISP and nothing more; they
343 * need to access local IPv6 addresses. We rely on the 6bed4 port being
344 * 0 to decide that an address cannot be anything but a local override.
345 * Define LOCAL_OVERRIDES_PORT0 to enable this feature.
347 #ifdef LOCAL_OVERRIDES_PORT0
348 static inline bool is_local_override (struct in6_addr *ip6) {
349 return ip6->s6_addr16 [6] == 0;
352 #define is_local_override(_) false
356 * Test if the provided IPv6 address matches the prefix used for 6bed4.
358 static inline bool is_6bed4 (struct in6_addr *ip6) {
359 return memcmp (&v6listen, ip6->s6_addr, 8) == 0;
364 * Validate the originator's IPv6 address. It should match the
365 * UDP/IPv4 coordinates of the receiving 6bed4 socket. Also,
366 * the /64 prefix must match that of v6listen.
368 bool validate_originator (struct sockaddr_in *sin, struct in6_addr *ip6) {
369 uint16_t port = ntohs (sin->sin_port);
370 uint32_t addr = ntohl (sin->sin_addr.s_addr);
372 if (!is_6bed4 (ip6)) {
375 if ((port & 0xff) != ip6->s6_addr [13]) {
378 if ((port >> 8) != ip6->s6_addr [12]) {
381 if (addr != ((ntohl(ip6->s6_addr32 [2]) & 0xfcffffff) | (((uint32_t) ip6->s6_addr [14] & 0xc0) << 18))) {
389 * Major packet processing functions
394 * Respond to a Router Solicitation received over the 6bed4 Network.
396 void handle_6bed4_router_solicit (void) {
397 struct in6_addr observed;
398 v4v6icmptype = ND_ROUTER_ADVERT;
399 v4v6icmpdata [0] = 0; // Cur Hop Limit: unspec
400 v4v6icmpdata [1] = 0x18; // M=0, O=0
403 // TODO: wire says 0x44 for router_adv.flags
405 memset (v4v6icmpdata+writepos, 0xff, 2+4+4);
406 // Router Lifetime: max, 18.2h
407 // Reachable Time: max
408 // Retrans Timer: max
410 writepos = icmp6_prefix (writepos, 0);
411 //TODO:DEPRECATED// writepos = icmp6_dest_linkaddr (writepos);
412 memcpy (&observed, v6listen_linklocal, 8);
413 addr_6bed4(&observed, (uint8_t *) &v4name.sin_addr.s_addr, ntohs(v4name.sin_port), 1);
414 icmp6_reply (writepos);
418 /* Handle the IPv4 message pointed at by msg as a neighbouring command.
420 * Type Code ICMPv6 meaning Handling
421 * ---- ---- ----------------------------- ----------------------------
422 * 133 0 Router Solicitation Send Router Advertisement
423 * 134 0 Router Advertisement Ignore
424 * 135 0 Neighbour Solicitation Send Neighbour Advertisement
425 * 136 0 Neighbour Advertisement Ignore
426 * 137 0 Redirect Ignore
428 void handle_4to6_nd (ssize_t v4ngbcmdlen) {
429 uint16_t srclinklayer;
430 if (v4ngbcmdlen < sizeof (struct ip6_hdr) + sizeof (struct icmp6_hdr)) {
433 if (v4v6icmpcode != 0) {
436 if (icmp6_checksum (v4ngbcmdlen - sizeof (struct ip6_hdr)) != v4v6icmpcksum) {
440 // Approved. Perform neighbourly courtesy.
441 switch (v4v6icmptype) {
442 case ND_ROUTER_SOLICIT:
444 // Validate Router Solicitation
446 if (v4ngbcmdlen == sizeof (struct ip6_hdr) + 8 + 8) {
447 // One option is possible, the source link-layer address
448 if (v4v6icmpdata [4] != 1 || v4v6icmpdata [5] != 1) {
449 break; /* bad opton, ignore */
451 // The source link-layer address is end-aligned
452 srclinklayer = (v4v6icmpdata [10] << 8) | v4v6icmpdata [11];
453 if (srclinklayer == 0) {
454 break; /* illegal, ignore */
456 } else if (v4ngbcmdlen == sizeof (struct ip6_hdr) + 8) {
457 srclinklayer = 0; /* set for latter filling */
459 break; /* illegal length, drop */
462 // Having accepted the Router Advertisement, respond
463 handle_6bed4_router_solicit ();
465 case ND_NEIGHBOR_SOLICIT:
467 // Validate Neigbour Solicitation
468 if (!validate_originator (&v4name, v4src6)) {
469 break; /* bad source address, drop */
471 if ((v4ngbcmdlen != sizeof (struct ip6_hdr) + 24) &&
472 (v4ngbcmdlen != sizeof (struct ip6_hdr) + 24 + 8)) {
473 break; /* funny length, drop */
475 if ((memcmp (v4ngbsoltarget, v6listen_linklocal, 16) != 0) &&
476 (memcmp (v4ngbsoltarget, v6listen_linklocal_complete, 16) != 0) &&
477 (memcmp (v4ngbsoltarget, &v6listen_complete, 16) != 0)) {
478 break; /* target not known here, drop */
481 // Construct Neigbour Advertisement
482 v4v6icmptype = ND_NEIGHBOR_ADVERT;
483 v4v6icmpdata [0] = 0xc0;
486 v4v6icmpdata [3] = 0x00; // R=1, S=1, O=1, Reserved=0
487 memcpy (v4v6icmpdata + 4, &v6listen_complete, 16);
488 // Append option: the target link-layer address
489 // Note: wire does not include target link-layer address
490 v4v6icmpdata [20] = 2; // Type: Target Link-Layer Addr
491 v4v6icmpdata [21] = 1; // Length: 1x 8 bytes
492 memcpy (v4v6icmpdata + 22, lladdr_6bed4, 6);
493 icmp6_reply (28); // 28 is the ICMPv6 response length
495 case ND_ROUTER_ADVERT:
496 case ND_NEIGHBOR_ADVERT:
504 * Forward a message received over the 6bed4 Network over IPv6.
505 * Note that existing checksums will work well, as only the
506 * Hop Limit has been altered, and this is not part of the
507 * checksum calculations.
509 void handle_4to6_plain_unicast (ssize_t v4datalen) {
510 printf ("Writing IPv6, result = %zd\n",
511 write (v6sox, &v4data6, sizeof (struct tun_pi) + v4datalen));
516 * Forward a 6bed4 message to another 6bed4 destination address.
517 * Note that existing checksums will work well, as only the
518 * Hop Limit has been altered, and this is not part of the
519 * checksum calculations.
521 void relay_6bed4_plain_unicast (uint8_t* data, ssize_t v4datalen, struct in6_addr *ip6) {
522 v4name.sin_port = htons (ip6->s6_addr [12] << 8 | ip6->s6_addr [13]);
523 uint8_t *addr = (uint8_t *) &v4name.sin_addr.s_addr;
524 addr [0] = (ip6->s6_addr [8] & 0xfc) | ip6->s6_addr [14] >> 6;
525 memcpy (addr + 1, ip6->s6_addr + 9, 3);
526 printf ("Relaying over 6bed4 Network to %d.%d.%d.%d:%d, result = %zd\n",
527 ((uint8_t *) &v4name.sin_addr.s_addr) [0],
528 ((uint8_t *) &v4name.sin_addr.s_addr) [1],
529 ((uint8_t *) &v4name.sin_addr.s_addr) [2],
530 ((uint8_t *) &v4name.sin_addr.s_addr) [3],
531 ntohs (v4name.sin_port),
535 (struct sockaddr *) &v4name, sizeof (v4name)));
539 /* Receive a tunnel package, and route it to either the handler for the
540 * tunnel protocol, or to the handler that checks and then unpacks the
543 void handle_4to6 (void) {
546 socklen_t adrlen = sizeof (v4name);
548 // Receive IPv4 package, which may be tunneled or a tunnel request
549 buflen = recvfrom (v4sox,
552 (struct sockaddr *) &v4name, &adrlen
555 printf ("%s: Error receiving IPv4-side package: %s",
556 program, strerror (errno));
559 if (buflen < sizeof (struct ip6_hdr)) {
562 if ((v4data [0] & 0xf0) != 0x60) {
563 // Not an IPv6 packet
567 // Handle the tunneled IPv6 package (dependent on its class)
568 if ((v4v6nexthdr == IPPROTO_ICMPV6) &&
569 (v4v6icmptype >= 133) && (v4v6icmptype <= 137)) {
571 // Not Plain: Router Adv/Sol, Neighbor Adv/Sol, Redirect
572 if (v4v6hoplimit != 255) {
575 handle_4to6_nd (buflen);
576 } else if ((v4dst6->s6_addr [0] != 0xff) && !(v4dst6->s6_addr [8] & 0x01)) {
579 if (is_local_override (v4dst6)) {
580 handle_4to6_plain_unicast (buflen);
581 } else if (validate_originator (&v4name, v4src6)) {
582 if (v4v6hoplimit-- <= 1) {
585 if (is_6bed4 (v4dst6)) {
586 relay_6bed4_plain_unicast (v4data, buflen, v4dst6);
588 handle_4to6_plain_unicast (buflen);
590 } else if (is_6bed4 (v4src6)) {
591 // The sender must not have kept NAT/firewall holes
592 // open and should be instructed about a change in
593 // its 6bed4 Link-Local Address.
594 handle_6bed4_router_solicit ();
599 //OPTIONAL// validate_originator, hoplimit, relay_mcast.
605 /* Receive an IPv6 package, check its address and pickup IPv4 address and
606 * port, then package it as a tunnel message and forward it to IPv4:port.
608 void handle_6to4 (void) {
610 // Receive the IPv6 package and ensure a consistent size
611 size_t rawlen = read (v6sox, &v6data6, sizeof (v6data6));
613 return; /* error reading, drop */
615 if (rawlen < sizeof (struct tun_pi) + sizeof (struct ip6_hdr) + 1) {
616 return; /* too small, drop */
618 if (v6tuncmd.proto != htons (ETH_P_IPV6)) {
619 return; /* no IPv6, drop */
621 if ((v6nexthdr == IPPROTO_ICMPV6) &&
622 (v6icmptype >= 133) && (v6icmptype <= 137)) {
623 return; /* not plain IPv6, drop */
625 if (v6hoplimit-- <= 1) {
626 // TODO: Send back an ICMPv6 error message
627 return; /* hop limit exceeded, drop */
629 if ((v6dst6->s6_addr [0] == 0xff) /* TODO:UDP_PORT_NOT_YET_FORCED_TO_EVEN || (v6dst6->s6_addr [8] & 0x01) */ ) {
630 printf ("Received multicast IPv6 data, flags=0x%04x, proto=0x%04x\n", v6tuncmd.flags, v6tuncmd.proto);
631 //OPTIONAL// handle_6to4_plain_multicast ()
632 return; /* multicast, drop */
634 printf ("Received plain unicast IPv6 data, flags=0x%04x, proto=0x%04x\n", v6tuncmd.flags, v6tuncmd.proto);
636 // Ensure that the incoming IPv6 address is properly formatted
637 // Note that this avoids access to ::1/128, fe80::/10, fec0::/10
638 if (memcmp (v6dst6, &v6listen, 8) != 0) {
642 // Harvest socket address data from destination IPv6, then send
643 relay_6bed4_plain_unicast (v6data, rawlen - sizeof (struct tun_pi), v6dst6);
647 /* Run the daemon core code, passing information between IPv4 and IPv6 and
648 * responding to tunnel requests if so requested.
650 void run_daemon (void) {
655 int nfds = (v4sox < v6sox)? (v6sox + 1): (v4sox + 1);
657 select (nfds, &io, NULL, NULL, NULL);
658 if (FD_ISSET (v4sox, &io)) {
663 if (FD_ISSET (v6sox, &io)) {
673 /* Option descriptive data structures */
675 char *short_opt = "l:L:t:h";
677 struct option long_opt [] = {
678 { "v4listen", 1, NULL, 'l' },
679 { "v6prefix", 1, NULL, 'L' },
680 { "tundev", 1, NULL, 't' },
681 { "help", 0, NULL, 'h' },
682 { NULL, 0, NULL, 0 } /* Array termination */
685 /* Parse commandline arguments (and start to process them).
686 * Return 1 on success, 0 on failure.
688 int process_args (int argc, char *argv []) {
690 int help = (argc == 1);
693 switch (getopt_long (argc, argv, short_opt, long_opt, NULL)) {
696 if (optind != argc) {
697 fprintf (stderr, "%s: Extra arguments not permitted: %s...\n", program, argv [optind]);
704 fprintf (stderr, "%s: Only one -l argument is permitted\n", program);
708 if (inet_pton (AF_INET, optarg, &v4name.sin_addr) <= 0) {
710 fprintf (stderr, "%s: Failed to parse IPv4 address %s\n", program, optarg);
713 memcpy (&v4listen, &v4name.sin_addr, 4);
714 v4sox = socket (AF_INET, SOCK_DGRAM, 0);
717 fprintf (stderr, "%s: Failed to allocate UDPv4 socket: %s\n", program, strerror (errno));
720 if (bind (v4sox, (struct sockaddr *) &v4name, sizeof (v4name)) != 0) {
722 fprintf (stderr, "%s: Failed to bind to UDPv4 %s:%d: %s\n", program, optarg, ntohs (v4name.sin_port), strerror (errno));
729 fprintf (stderr, "%s: Only one -L argument is permitted\n", program);
732 char *slash64 = strchr (optarg, '/');
733 if (!slash64 || strcmp (slash64, "/64") != 0) {
735 fprintf (stderr, "%s: The -L argument must be an explicit /64 prefix and not %s\n", program, slash64? slash64: "implied");
739 v6server = strdup (optarg);
742 if (!v6server || inet_pton (AF_INET6, v6server, &v6listen) <= 0) {
744 fprintf (stderr, "%s: Failed to parse IPv6 prefix %s\n", program, optarg);
747 if (v6listen.s6_addr32 [2] || v6listen.s6_addr32 [3]) {
749 fprintf (stderr, "%s: IPv6 prefix contains bits beyond its /64 prefix: %s\n", program, optarg);
756 fprintf (stderr, "%s: Multiple -t arguments are not permitted\n", program);
759 v6sox = open (optarg, O_RDWR);
762 fprintf (stderr, "%s: Failed to open tunnel device %s: %s\n", program, optarg, strerror (errno));
769 /* continue into 'h' to produce usage information */
779 #ifdef HAVE_SETUP_TUNNEL
780 fprintf (stderr, "Usage: %s [-t /dev/tunX] -l <v4server> -L <v6prefix>/64\n %s -h\n", program, program);
782 fprintf (stderr, "Usage: %s -t /dev/tunX -l <v4server> -L <v6prefix>/64\n %s -h\n", program, program);
790 fprintf (stderr, "%s: Use -l to specify an IPv4 address for the tunnel interface\n", program);
794 fprintf (stderr, "%s: Use -L to specify a /64 prefix on the IPv6 side\n", program);
797 #ifdef HAVE_SETUP_TUNNEL
799 if (geteuid () != 0) {
800 fprintf (stderr, "%s: You should be root, or use -t to specify an accessible tunnel device\n", program);
803 ok = setup_tunnel ();
805 #else /* ! HAVE_SETUP_TUNNEL */
807 fprintf (stderr, "%s: You must specify a tunnel device with -t that is accessible to you\n", program);
810 #endif /* HAVE_SETUP_TUNNEL */
815 /* The main program parses commandline arguments and forks off the daemon
817 int main (int argc, char *argv []) {
821 memset (&v4name, 0, sizeof (v4name));
822 memset (&v6name, 0, sizeof (v6name));
823 v4name.sin_family = AF_INET ;
824 v6name.sin6_family = AF_INET6;
825 v4name.sin_port = htons (UDP_PORT_6BED4); /* 6BED4 standard port */
827 v4tunpi6.proto = htons (ETH_P_IPV6);
829 // Parse commandline arguments
830 if (!process_args (argc, argv)) {
834 // Setup a few addresses for later comparison/reproduction
835 // * lladdr_6bed4 is the 6bed4 Link-Local Address
836 // * v6listen_complete is the router's full IPv6 address (with if-id)
837 // * v6listen_linklocal_complete is fe80::/64 plus the router's if-id
838 // A few others have already been setup at this time
839 // * v6listen is the router's 6bed4 prefix ending in 64 zero bits
840 // * v6listen_linklocal is the address fe80::/128
842 lladdr_6bed4 [0] = UDP_PORT_6BED4 & 0xff;
843 lladdr_6bed4 [1] = UDP_PORT_6BED4 >> 8;
844 memcpy (lladdr_6bed4 + 2, (uint8_t *) &v4name.sin_addr, 4);
845 memcpy (&v6listen_complete, &v6listen, 8);
846 addr_6bed4(&v6listen_complete, lladdr_6bed4 + 2, ntohs(v4name.sin_port), 0);
848 memcpy (v6listen_linklocal_complete, v6listen_linklocal, 8);
849 memcpy (v6listen_linklocal_complete + 8, &v6listen_complete.s6_addr [8], 8);
850 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]);
851 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]));
852 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]));
853 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]));
854 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]));
856 // Start the main daemon process
857 #ifdef SKIP_TESTING_KLUDGE_IN_FOREGROUND
859 case -1: /* Error forking */
860 fprintf (stderr, "%s: Failed to fork: %s\n", program, strerror (errno));
862 case 0: /* Child process */
864 //TODO: tmp.support for ^printf// close (1);
869 default: /* Parent process */
878 // Report successful creation of the daemon