1 /* 6bed4/peer.c -- Peer-to-Peer IPv6-anywhere with 6bed4 -- peer.c
3 * This is an implementation of neighbour and router discovery over a
4 * tunnel that packs IPv6 inside UDP/IPv4. This tunnel mechanism is
5 * so efficient that the server administrators need not mind if it is
8 * From: Rick van Rein <rick@openfortress.nl>
26 #define LOG_PERROR LOG_CONS /* LOG_PERROR is non-POSIX, LOG_CONS is */
29 #include <sys/types.h>
30 #include <sys/socket.h>
32 #include <sys/select.h>
33 #include <sys/ioctl.h>
37 #include <netinet/in.h>
38 #include <netinet/ip.h>
39 #include <netinet/ip6.h>
40 #include <netinet/udp.h>
41 #include <netinet/icmp6.h>
42 #include <arpa/inet.h>
44 #include <asm/types.h>
45 //#include <linux/if.h>
46 #include <linux/if_tun.h>
47 #include <linux/if_ether.h>
48 #include <linux/netlink.h>
49 #include <linux/rtnetlink.h>
51 /* The following will initially fail, due to an IANA obligation to avoid
52 * default builds with non-standard options.
58 #define PREFIX_SIZE 114
67 * The HAVE_SETUP_TUNNEL variable is used to determine whether absense of
68 * the -d option leads to an error, or to an attempt to setup the tunnel.
69 * The setup_tunnel() function used for that is defined per platform, such
70 * as for LINUX. Remember to maintain the manpage's optionality for -d.
72 #undef HAVE_SETUP_TUNNEL
75 #ifndef MAX_ROUTABLE_PREFIXES
76 #define MAX_ROUTABLE_PREFIXES 10
80 /* Global variables */
85 volatile int signalnum = 0;
92 uint8_t v4qos = 0; /* Current QoS setting on UDP/IPv4 socket */
93 uint32_t v6tc = 0; /* Current QoS used by the IPv6 socket */
94 uint8_t v4ttl = 64; /* Default TTL setting on UDP/IPv4 socket */
95 int v4ttl_mcast = -1; /* Multicast TTL for LAN explorations */
97 char *v4server = NULL;
98 char *v6server = NULL;
99 char v6prefix [INET6_ADDRSTRLEN];
100 uint8_t v6lladdr [6];
102 struct in6_addr v6route_addr [MAX_ROUTABLE_PREFIXES];
103 uint8_t v6route_pfix [MAX_ROUTABLE_PREFIXES];
104 int v6route_count = 0;
106 const uint8_t v6listen_linklocal [16] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
107 uint8_t v6listen_linklocal_complete [16] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
109 struct sockaddr_nl rtname;
110 struct sockaddr_nl rtkernel;
112 struct sockaddr_in v4name;
113 struct sockaddr_in v4peer;
114 struct sockaddr_in6 v6name;
116 struct sockaddr_in v4bind;
117 struct sockaddr_in v4allnodes;
119 struct in6_addr v6listen;
120 //TODO:NEEDNOT// struct in6_addr v6listen_complete;
121 struct in_addr v4listen;
132 struct ip6_hdr v6hdr;
133 uint8_t data [MTU - sizeof (struct ip6_hdr)];
136 struct ip6_hdr v6hdr;
137 struct icmp6_hdr v6icmphdr;
140 } __attribute__((packed)) v4data6;
143 #define v4ether (v4data6.eth)
145 #define v4tunpi6 (v4data6.tun)
147 #define v4data ((uint8_t *) &v4data6.udata)
148 #define v4hdr6 (&v4data6.udata.idata.v6hdr)
149 #define v4src6 (&v4data6.udata.idata.v6hdr.ip6_src)
150 #define v4dst6 (&v4data6.udata.idata.v6hdr.ip6_dst)
152 #define v4v6plen (v4data6.udata.ndata.v6hdr.ip6_plen)
153 #define v4v6nexthdr (v4data6.udata.ndata.v6hdr.ip6_nxt)
154 #define v4v6hoplimit (v4data6.udata.ndata.v6hdr.ip6_hops)
156 #define v4icmp6 (&v4data6.udata.ndata.v6icmphdr)
157 #define v4v6icmpdata (v4data6.udata.ndata.v6icmphdr.icmp6_data8)
158 #define v4v6icmptype (v4data6.udata.ndata.v6icmphdr.icmp6_type)
159 #define v4v6icmpcode (v4data6.udata.ndata.v6icmphdr.icmp6_code)
160 #define v4v6icmpcksum (v4data6.udata.ndata.v6icmphdr.icmp6_cksum)
161 #define v4v6ndtarget (&v4data6.udata.ndata.v6icmphdr.icmp6_data8 [4])
173 struct ip6_hdr v6hdr;
174 struct icmp6_hdr v6icmp;
175 } __attribute__((packed)) ndata;
177 } __attribute__((packed)) v6data6;
180 #define v6ether (v6data6.eth)
182 #define v6tuncmd (v6data6.tun)
184 #define v6data (v6data6.udata.data)
185 #define v6hdr6 (&v6data6.udata.ndata.v6hdr)
186 #define v6hops (v6data6.udata.ndata.v6hdr.ip6_hops)
187 #define v6type (v6data6.udata.ndata.v6hdr.ip6_nxt)
188 #define v6plen (v6data6.udata.ndata.v6hdr.ip6_plen)
189 #define v6src6 (&v6data6.udata.ndata.v6hdr.ip6_src)
190 #define v6dst6 (&v6data6.udata.ndata.v6hdr.ip6_dst)
191 #define v6icmp6type (v6data6.udata.ndata.v6icmp.icmp6_type)
192 #define v6icmp6code (v6data6.udata.ndata.v6icmp.icmp6_code)
193 #define v6icmp6data (v6data6.udata.ndata.v6icmp.icmp6_data8)
194 #define v6icmp6csum (v6data6.udata.ndata.v6icmp.icmp6_cksum)
195 #define v6ndtarget (&v6data6.udata.ndata.v6icmp.icmp6_data16[2])
198 #define HDR_SIZE (sizeof(struct ethhdr))
200 #define HDR_SIZE (sizeof(struct tun_pi))
203 /* Structure for tasks in neighbor discovery queues
206 struct ndqueue *next;
208 struct in6_addr source;
209 struct in6_addr target;
210 uint8_t source_lladdr [6];
211 uint8_t todo_lancast, todo_direct;
214 /* Round-robin queue for regular tasks, starting at previous value */
215 struct ndqueue *ndqueue = NULL;
216 struct ndqueue *freequeue = NULL;
217 uint32_t freequeue_items = 100;
219 /* The time for the next scheduled maintenance: routersol or keepalive.
220 * The milliseconds are always 0 for maintenance tasks.
222 time_t maintenance_time_sec;
223 time_t maintenance_time_cycle = 0;
224 time_t maintenance_time_cycle_max = 30;
225 bool got_lladdr = false;
226 time_t keepalive_period = 30;
227 time_t keepalive_ttl = -1;
229 /* The network packet structure of a 6bed4 Router Solicitation */
231 uint8_t ipv6_router_solicitation [] = {
233 0x60, 0x00, 0x00, 0x00,
234 16 >> 8, 16 & 0xff, IPPROTO_ICMPV6, 255,
235 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // unspecd src
236 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02, // all-rtr tgt
237 // ICMPv6 header: router solicitation
238 ND_ROUTER_SOLICIT, 0, 0x7a, 0xae, // Checksum courtesy of WireShark :)
239 // ICMPv6 body: reserved
241 // ICMPv6 option: source link layer address 0x0001 (end-aligned)
242 0x01, 0x01, 0, 0, 0, 0, 0x00, 0x01,
245 uint8_t ipv6_defaultrouter_neighbor_advertisement [] = {
247 0x60, 0x00, 0x00, 0x00,
248 32 >> 8, 32 & 0xff, IPPROTO_ICMPV6, 255,
249 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // src is default router
250 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01,// dst is all-nodes multicast, portable?
251 // ICMPv6 header: neighbor solicitation
252 ND_NEIGHBOR_ADVERT, 0, 0x36, 0xf2, // Checksum courtesy of WireShark :)
253 // ICMPv6 Neighbor Advertisement: flags
256 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // the targeted neighbor
257 // ICMPv6 option: target link layer address
259 UDP_PORT_6BED4 & 0xff, UDP_PORT_6BED4 >> 8,
260 SERVER_6BED4_IPV4_INT0, SERVER_6BED4_IPV4_INT1, SERVER_6BED4_IPV4_INT2, SERVER_6BED4_IPV4_INT3
263 uint8_t router_linklocal_address [] = {
264 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00,
267 //TODO// Complete with the if-id of the 6bed4 Router:
268 uint8_t router_linklocal_address_complete [] = {
269 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00,
272 uint8_t client1_linklocal_address [] = {
273 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01,
276 uint8_t allnodes_linklocal_address [] = {
277 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01,
280 uint8_t allrouters_linklocal_address [] = {
281 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x02,
284 uint8_t solicitednodes_linklocal_prefix [13] = {
285 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0xff
288 bool default_route = false;
290 bool foreground = false;
292 bool log_to_stderr = false;
294 bool multicast = true;
303 #ifndef INTERFACE_NAME_6BED4
304 #define INTERFACE_NAME_6BED4 "6bed4"
308 #define HAVE_SETUP_TUNNEL
309 static struct ifreq ifreq;
310 static bool have_tunnel = false;
311 /* Implement the setup_tunnel() command for Linux.
312 * Return true on success, false on failure.
314 bool setup_tunnel (void) {
316 v6sox = open ("/dev/net/tun", O_RDWR);
319 syslog (LOG_ERR, "%s: Failed to access tunnel driver on /dev/net/tun: %s\n", program, strerror (errno));
323 int flags = fcntl (v6sox, F_GETFL, 0);
325 syslog (LOG_CRIT, "Failed to retrieve flags for the tunnel file descriptor: %s\n", strerror (errno));
329 memset (&ifreq, 0, sizeof (ifreq));
330 strncpy (ifreq.ifr_name, INTERFACE_NAME_6BED4, IFNAMSIZ);
332 ifreq.ifr_flags = IFF_TAP | IFF_NO_PI;
334 ifreq.ifr_flags = IFF_TUN;
336 if (ok && (ioctl (v6sox, TUNSETIFF, (void *) &ifreq) == -1)) {
337 syslog (LOG_CRIT, "Failed to set interface name: %s\n", strerror (errno));
342 ifreq.ifr_name [IFNAMSIZ] = 0;
343 ifreq.ifr_ifindex = if_nametoindex (ifreq.ifr_name);
344 syslog (LOG_DEBUG, "Found Interface Index %d for name %s\n", ifreq.ifr_ifindex, ifreq.ifr_name);
345 ok = ok & (ifreq.ifr_ifindex != 0);
348 snprintf (cmd, 512, "/sbin/sysctl -q -w net.ipv6.conf.%s.forwarding=0", ifreq.ifr_name);
349 if (ok && system (cmd) != 0) {
350 fprintf (stderr, "Failed command: %s\n", cmd);
353 snprintf (cmd, 512, "/sbin/sysctl -q -w net.ipv6.conf.%s.accept_dad=0", ifreq.ifr_name);
354 if (ok && system (cmd) != 0) {
355 fprintf (stderr, "Failed command: %s\n", cmd);
359 close (v6sox); /* This removes the tunnel interface */
365 bool setup_tunnel_address (void) {
366 bool ok = have_tunnel;
369 snprintf (cmd, 512, "/sbin/sysctl -q -w net.ipv6.conf.%s.autoconf=0", ifreq.ifr_name);
370 if (ok && system (cmd) != 0) {
373 snprintf (cmd, 512, "/sbin/ip link set %s up mtu %d", ifreq.ifr_name, MTU);
374 if (ok && system (cmd) != 0) {
375 fprintf (stderr, "Failed command: %s\n", cmd);
378 snprintf (cmd, 512, "/sbin/ip -6 addr add %s/114 dev %s", v6prefix, ifreq.ifr_name);
379 if (ok && system (cmd) != 0) {
380 fprintf (stderr, "Failed command: %s\n", cmd);
384 snprintf (cmd, 512, "/sbin/ip -6 route add default via fe80:: dev %s metric 1042", ifreq.ifr_name);
385 if (ok && system (cmd) != 0) {
386 fprintf (stderr, "Failed command: %s\n", cmd);
390 for (int i = 0; i < v6route_count; i++) {
391 snprintf (cmd, 512, "/sbin/ip -6 route add %x:%x:%x:%x:%x:%x:%x:%x/%d via fe80:: dev %s metric 1052", ntohs (v6route_addr [i].s6_addr16 [0]), ntohs (v6route_addr [i].s6_addr16 [1]), ntohs (v6route_addr [i].s6_addr16 [2]), ntohs (v6route_addr [i].s6_addr16 [3]), ntohs (v6route_addr [i].s6_addr16 [4]), ntohs (v6route_addr [i].s6_addr16 [5]), ntohs (v6route_addr [i].s6_addr16 [6]), ntohs (v6route_addr [i].s6_addr16 [7]), v6route_pfix [i], ifreq.ifr_name);
392 if (ok && system (cmd) != 0) {
393 fprintf (stderr, "Failed command: %s\n", cmd);
405 * Extension Hook Functions
410 /* Extension hook to deliver a new IPv6 address range that others may use.
412 void exthook_add_range_offer (struct in6_addr *start, struct in6_addr *end) {
413 if (exthook == NULL) {
416 char startstr [INET6_ADDRSTRLEN+1];
417 char endstr [INET6_ADDRSTRLEN+1];
418 inet_ntop (AF_INET6, start, startstr, INET6_ADDRSTRLEN);
419 inet_ntop (AF_INET6, end, endstr, INET6_ADDRSTRLEN);
421 snprintf (cmd, 512, "%s %d add-range-offer %s %s",
424 if (system (cmd) != 0) {
425 fprintf (stderr, "Hook failed: %s\n", cmd);
430 /* Extension hook to deliver a new IPv6 route.
432 void exthook_add_route_offer (struct in6_addr *pfaddr, uint8_t pflen,
433 struct in6_addr *router) {
434 if (exthook == NULL) {
437 char pfaddrstr [INET6_ADDRSTRLEN+1];
438 char routerstr [INET6_ADDRSTRLEN+1];
439 inet_ntop (AF_INET6, pfaddr, pfaddrstr, INET6_ADDRSTRLEN);
440 inet_ntop (AF_INET6, router, routerstr, INET6_ADDRSTRLEN);
442 snprintf (cmd, 512, "%s %d add-route-offer %s %d %s",
444 pfaddrstr, pflen, routerstr);
445 if (system (cmd) != 0) {
446 fprintf (stderr, "Hook failed: %s\n", cmd);
451 /* Extension hook to remove past offers by this process.
452 * This one is special; it is run during orderly shutdown.
454 void exthook_del_offers (void) {
455 if (exthook == NULL) {
459 snprintf (cmd, 512, "%s %d del-offers",
461 if (system (cmd) != 0) {
462 fprintf (stderr, "Hook failed: %s\n", cmd);
475 /* Produce an IPv6 address following the 6bed4 structures.
476 * - The top half is taken from v6listen
477 * - The bottom contains IPv4 address and port from v4name
478 * - The last 14 bits are filled with the lanip parameter
480 void addr_6bed4 (struct in6_addr *dst_ip6, uint16_t lanip) {
481 memcpy (&dst_ip6->s6_addr [0], &v6listen, 8);
482 dst_ip6->s6_addr32 [2] = v4name.sin_addr.s_addr;
483 dst_ip6->s6_addr16 [6] = v4name.sin_port;
484 dst_ip6->s6_addr [14] = ((dst_ip6->s6_addr [8] & 0x03) << 6)
485 | ((lanip >> 8) & 0x3f);
486 dst_ip6->s6_addr [15] = (lanip & 0xff);
487 dst_ip6->s6_addr [8] &= 0xfc;
491 /* Look for an entry in the 50ms-cycled Neighbor Discovery queue.
492 * Match the target address. Return the entry found, or NULL.
494 struct ndqueue *findqueue (struct in6_addr *target) {
495 struct ndqueue *ndq = ndqueue;
498 if (memcmp (target, &ndq->target, 16) == 0) {
502 } while (ndq != ndqueue);
507 /* Enter an item in the 50ms-cycled Neighbor Discovery queue.
508 * Retrieve its storage space from the free queue.
509 * TODO: Avoid double entries by looking up entries first -> "requeue?"
511 static int TODO_qlen;
512 void enqueue (struct in6_addr *target, struct in6_addr *v6src, uint8_t *source_lladdr) {
514 // Refuse to create double entries
515 if (findqueue (target)) {
519 // Allocate a free item to enqueue
520 struct ndqueue *new = freequeue;
522 // Temporarily overflown with ND -> drop the request
525 char tgt [INET6_ADDRSTRLEN]; inet_ntop (AF_INET6, target, tgt, sizeof (tgt));
526 syslog (LOG_DEBUG, "Queue++ => %d, looking for %s\n", ++TODO_qlen, tgt);
527 freequeue = freequeue->next;
529 // Setup the new entry with target details
530 memcpy (&new->target, target, sizeof (new->target));
531 memcpy (&new->source, v6src, sizeof (new->source));
532 memcpy (&new->source_lladdr, source_lladdr, sizeof (new->source_lladdr));
533 new->todo_lancast = (v4mcast == -1)? 0: 2;
534 new->todo_direct = 3;
536 // Time the new item to run instantly
539 // Enqueue the new item in front of the queue
541 new->next = ndqueue->next;
549 /* Remove an item from the 50ms-cycled Neighbor Discovery queue.
550 * Enter its storage space in the free queue.
552 void dequeue (struct ndqueue *togo) {
553 struct ndqueue *prev = ndqueue;
555 if (prev->next == togo) {
556 if (togo->next != togo) {
557 prev->next = togo->next;
558 if (ndqueue == togo) {
559 ndqueue = togo->next;
562 // Must be the only queued item
565 togo->next = freequeue;
567 syslog (LOG_DEBUG, "Queue-- => %d\n", --TODO_qlen);
571 } while (prev != ndqueue);
576 * Calculate the ICMPv6 checksum field
578 uint16_t icmp6_checksum (uint8_t *ipv6hdr, size_t payloadlen) {
579 uint16_t plenword = htons (payloadlen);
580 uint16_t nxthword = htons (IPPROTO_ICMPV6);
581 uint16_t *areaptr [] = { (uint16_t *) &ipv6hdr [8], (uint16_t *) &ipv6hdr [24], &plenword, &nxthword, (uint16_t *) &ipv6hdr [40], (uint16_t *) &ipv6hdr [40 + 4] };
582 uint8_t areawords [] = { 8, 8, 1, 1, 1, payloadlen/2 - 2 };
585 for (i=0; i < 6; i++) {
586 uint16_t *area = areaptr [i];
587 for (j=0; j<areawords [i]; j++) {
588 csum += ntohs (area [j]);
591 csum = (csum & 0xffff) + (csum >> 16);
592 csum = (csum & 0xffff) + (csum >> 16);
593 csum = htons (~csum);
599 * Send a Redirect reply. This is in response to a v4v6data message,
600 * and is directed straight at the origin's address but sent with a
603 * Note: Although the packet arrived in v4data6, the reply is built
604 * in v6data6 and sent from there as though it had come from
607 void redirect_reply (uint8_t *ngbc_llremote, metric_t ngbc_metric) {
608 void handle_6to4_plain_unicast (const ssize_t pktlen, const uint8_t *lladdr);
609 v6icmp6type = ND_REDIRECT;
614 v6icmp6data [3] = 0; // Reserved
615 memcpy (v6icmp6data + 4, &v6listen, 16);
616 // Target IPv6 address
617 switch (ngbc_metric) {
618 // Destination Address suggestion
621 // Redirect to the local-subnet IPv4 address
622 memcpy (v6icmp6data + 4 + 16, v6listen_linklocal, 8);
623 v6icmp6data [4 + 16 + 8 ] = v4peer.sin_port & 0x00ff;
624 v6icmp6data [4 + 16 + 9 ] = v4peer.sin_port >> 8;
625 memcpy (v6icmp6data + 4 + 16 + 12, &v4peer.sin_addr, 4);
626 v6icmp6data [4 + 16 + 10] = v4v6icmpdata [4 + 16 + 12];
627 v6icmp6data [4 + 16 + 11] = 0xff;
628 v6icmp6data [4 + 16 + 12] = 0xfe;
631 memcpy (v6icmp6data + 4 + 16, v6listen_linklocal_complete, 16);
635 return; /* no cause for Redirect, drop */
637 v6type = IPPROTO_ICMPV6;
638 v6plen = htons (8 + 16 + 16);
639 memcpy (v6src6, &v6listen, 16);
640 memcpy (v6dst6, v4src6, 16);
641 v6icmp6csum = icmp6_checksum ((uint8_t *) v4hdr6, 8 + 16 + 16);
642 handle_6to4_plain_unicast (HDR_SIZE + 40 + 8 + 16 + 16, ngbc_llremote);
646 /* Append the current prefix to an ICMPv6 message. Incoming optidx
647 * and return values signify original and new offset for ICMPv6 options.
648 * The endlife parameter must be set to obtain zero lifetimes, thus
649 * instructing the tunnel client to stop using an invalid prefix.
651 size_t icmp6_prefix (size_t optidx, uint8_t endlife) {
652 v6icmp6data [optidx++] = 3; // Type
653 v6icmp6data [optidx++] = 4; // Length
654 v6icmp6data [optidx++] = 114; // This is a /114 prefix
655 #ifndef COMPENSATE_FOR_AUTOCONF
656 v6icmp6data [optidx++] = 0xc0; // L=1, A=1, Reserved1=0
658 //TODO// Temporary fix: "ip -6 addr add .../64 dev 6bed4"
659 v6icmp6data [optidx++] = 0x80; // L=1, A=0, Reserved1=0
661 memset (v6icmp6data + optidx, endlife? 0x00: 0xff, 8);
663 // Valid Lifetime: Zero / Infinite
664 // Preferred Lifetime: Zero / Infinite
665 memset (v6icmp6data + optidx, 0, 4);
668 addr_6bed4 ((struct in6_addr *) (v6icmp6data + optidx), 0);
676 * Construct a Neighbor Advertisement message, providing the
677 * Public 6bed4 Service as the link-local address.
679 * This is done immediately when the IPv6 stack requests the link-local
680 * address for fe80:: through Router Solicition. In addition, it is the
681 * fallback response used when attempts to contact the remote peer at its
682 * direct IPv4 address and UDP port (its 6bed4 address) fails repeatedly.
684 * This routine is called with info==NULL to respond to an fe80::
685 * Neighbor Solicitation, otherwise with an info pointer containing
686 * a target IPv6 address to service.
688 void advertise_6bed4_public_service (struct ndqueue *info) {
692 memcpy (v6ether.h_dest, info->source_lladdr, 6);
694 memcpy (v6ether.h_dest, v6ether.h_source, 6);
696 memcpy (v6ether.h_source, SERVER_6BED4_PORT_IPV4_MACSTR, 6);
698 memcpy (v6data, ipv6_defaultrouter_neighbor_advertisement, 8);
700 memcpy (v6dst6, &info->source, 16);
702 memcpy (v6dst6, v6src6, 16);
705 memcpy (v6src6, &info->target, 16);
707 memcpy (v6src6, router_linklocal_address_complete, 16);
709 //TODO:OVERWROTE// memcpy (v6data + 8, ipv6_defaultrouter_neighbor_advertisement + 8, 16);
710 memcpy (v6data + 8 + 16 + 16, ipv6_defaultrouter_neighbor_advertisement + 8 + 16 + 16, sizeof (ipv6_defaultrouter_neighbor_advertisement) - 8 - 16 - 16);
712 // Overwrite target only for queued requests
713 memcpy (&v6icmp6data [4], &info->target, 16);
715 v6icmp6csum = icmp6_checksum ((uint8_t *) v6hdr6, 32);
716 int sent = write (v6sox, &v6data6, HDR_SIZE + sizeof (ipv6_defaultrouter_neighbor_advertisement));
718 syslog (LOG_DEBUG, "TODO: Neighbor Discovery failed to contact directly -- standard response provided\n");
720 syslog (LOG_DEBUG, "TODO: Neighbor Discovery for Public 6bed4 Service -- standard response provided\n");
726 * Validate the originator's IPv6 address. It should match the
727 * UDP/IPv4 coordinates of the receiving 6bed4 socket. Also,
728 * the /64 prefix (but not the /114 prefix!) must match v6listen.
730 bool validate_originator (struct in6_addr *ip6) {
733 // Communication from the configured router is welcomed
734 //TODO// Why should we trust the ip6 address at face value?
735 if ((v4name.sin_addr.s_addr == v4peer.sin_addr.s_addr)
736 && (v4name.sin_port == v4peer.sin_port)) {
740 // Require non-local top halves to match our v6listen_linklocal address
741 //TODO// When do we receive local top halves?
742 //TODO// We should really be more flexible and allow fallback addrs
743 if (memcmp (ip6, v6listen_linklocal, 8) != 0) {
744 if (memcmp (&v6listen, ip6->s6_addr, 8) != 0) {
749 // Require the sender port to appear in its IPv6 address
750 if (v4name.sin_port != ip6->s6_addr16 [6]) {
754 // Require the sender address to appear in its IPv6 address
755 addr = ntohl (ip6->s6_addr32 [2]) & 0xfcffffff;
756 addr |= ((uint32_t) (ip6->s6_addr [14] & 0xc0)) << (24-6);
757 if (addr != ntohl (v4name.sin_addr.s_addr)) {
761 // We passed with flying colours
767 * Translate a Link-Local Address to its metric. The metrics are
768 * numbered so that a higher number indicates a more costly path
769 * over which to connect. The values of the metric should not be
770 * published, but be treated as an opaque value with a complete
771 * ordering (that is: <, <=, >=, > relations) defined on it.
773 metric_t lladdr_metric (uint8_t *lladdr) {
774 uint32_t ipv4 = * (uint32_t *) (lladdr + 2);
776 // Metric 2: The 6bed4 Router address
777 if (ipv4 == v4peer.sin_addr.s_addr) {
781 // Metric 0: Private Addresses, as per RFC 1918
782 if ((ipv4 & 0xff000000) == 0x0a000000) {
783 return METRIC_LOW; /* 10.0.0./8 */
785 if ((ipv4 & 0xffff0000) == 0xc0a80000) {
786 return METRIC_LOW; /* 192.168.0.0/16 */
788 if ((ipv4 & 0xfff00000) == 0xac100000) {
789 return METRIC_LOW; /* 172.16.0.0/12 */
792 // Metric 1: Direct IPv4 contact is any other address
793 // Correctness should be checked elsewhere
794 return METRIC_MEDIUM;
799 * Retrieve the Link-Local Address, if any, for a given 6bed4 Peer.
800 * Return true on success, false on failure to find it. The lladdr
801 * parameter is only overwritten in case of success.
803 * Obviously, there is a point where it is more efficient to not
804 * lookup the cache for every request, but to cache it locally
805 * and limit the lookup frequency. This low-traffic optimal version
806 * is used here for initial simplicity, and because this is a peer
807 * daemon and a reference implementation. But who knows what people
808 * will submit as patches...
810 * Note: This code is specific to Linux, but note that BSD also has a
811 * NetLink concept, so it may port without needing to resort to
812 * shell commands running slowly in separate processes.
813 * Note: The interface for Linux is under-documented. Work may be
814 * needed to handle exception situations, such as going over
815 * invisible boundaries on the number of neighbours. Similarly,
816 * the use of alignment macros is rather unclear. This is not
817 * how I prefer to write code, but it's the best I can do now.
819 bool lookup_neighbor (uint8_t *ipv6, uint8_t *lladdr) {
825 memset (&msg, 0, sizeof (struct nlmsghdr) + sizeof (struct ndmsg));
826 msg.hd.nlmsg_len = NLMSG_LENGTH (sizeof (msg.nd));
827 msg.hd.nlmsg_type = RTM_GETNEIGH;
828 msg.hd.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT /* | NLM_F_MATCH */;
829 msg.hd.nlmsg_pid = rtname.nl_pid;
830 msg.nd.ndm_family = AF_INET6;
831 msg.nd.ndm_state = NUD_REACHABLE | NUD_DELAY | NUD_PROBE | NUD_PERMANENT | NUD_STALE; // Ignored by the kernel?
832 msg.nd.ndm_ifindex = ifreq.ifr_ifindex; // Ignored by the kernel?
833 // How to select an IPv6 address? Ignored by the kernel?
835 struct rtattr *ra1 = (struct rtattr *) (((char *) &msg) + sizeof (struct nlmsghdr) + sizeof (struct ndmsg));
836 ra1->rta_type = NDA_DST; // lookup IPv6 address
837 ra1->rta_len = RTA_LENGTH(16);
838 msg.hd.nlmsg_len = NLMSG_ALIGN (msg.hd.nlmsg_len) + RTA_LENGTH (16);
839 memcpy (RTA_DATA (ra1), ipv6, 16);
841 if (send (rtsox, &msg, msg.hd.nlmsg_len, MSG_DONTWAIT) == -1) {
846 { char buf [INET6_ADDRSTRLEN]; inet_ntop (AF_INET6, ipv6, buf, sizeof (buf)); syslog (LOG_DEBUG, "Looking up v6addr %s\n", buf); }
847 while (recvlen = recv (rtsox, ((char *) &msg) + pos, sizeof (msg) - pos, MSG_DONTWAIT), recvlen > 0) {
848 syslog (LOG_DEBUG, "Message of %zd bytes from neighbor cache, total is now %zd\n", recvlen, pos + recvlen);
852 while (resp = (struct mymsg *) (((char *) &msg) + pos),
853 (pos + sizeof (struct nlmsghdr) <= recvlen) &&
854 (pos + resp->hd.nlmsg_len <= recvlen)) {
855 bool ok = true, match = false;
856 uint8_t *result = NULL;
857 if (resp->hd.nlmsg_type == NLMSG_DONE) {
859 } else if (resp->hd.nlmsg_type != RTM_NEWNEIGH) {
860 syslog (LOG_ERR, "Kernel sent an unexpected nlmsg_type 0x%02x, ending neighbor interpretation", resp->hd.nlmsg_type);
862 } else if (resp->nd.ndm_ifindex != ifreq.ifr_ifindex) {
863 // syslog (LOG_DEBUG, "Kernel sent interface index %d (looking for %d)", resp->nd.ndm_ifindex, ifreq.ifr_ifindex);
864 pos += resp->hd.nlmsg_len;
865 continue; //ACCEPT// ok = false;
866 } else if (resp->nd.ndm_family != AF_INET6) {
867 syslog (LOG_ERR, "Kernel reported unknown neighbor family %d", resp->nd.ndm_family);
870 if (!(resp->nd.ndm_state & (NUD_REACHABLE | NUD_DELAY | NUD_PROBE | NUD_PERMANENT | NUD_STALE))) {
871 syslog (LOG_ERR, "Kernel sent a funnily flagged interface state");
874 struct rtattr *ra = (struct rtattr *) ((char *) &resp + pos + sizeof (struct nlmsghdr) + sizeof (struct ndmsg) + 8);
876 while (ok && (rapos + ra->rta_len <= resp->hd.nlmsg_len)) {
877 switch (ra->rta_type) {
879 { char buf [INET6_ADDRSTRLEN]; inet_ntop (AF_INET6, RTA_DATA (ra), buf, sizeof (buf)); syslog (LOG_DEBUG, "Comparing against %s\n", buf); }
880 if (memcmp (ipv6, RTA_DATA (ra), 16) == 0) {
885 result = RTA_DATA (ra);
890 break; /* not of interest, skip */
892 rapos += ((ra->rta_len - 1) | 0x00000003) + 1;
893 ra = (struct rtattr *) (((char *) ra) + (((ra->rta_len - 1) | 0x0000003) + 1));
895 if (ok && match && result) {
896 memcpy (lladdr, result, 6);
897 return true; /* Yippy! Erfolg! */
899 pos += resp->hd.nlmsg_len;
901 // Copy remaining partial message to the beginning, continue from there
902 memcpy (&msg, ((char *) &msg) + pos, recvlen - pos);
910 * Major packet processing functions
914 /* Handle the IPv4 message pointed at by msg, checking if (TODO:HUH?) the IPv4:port
915 * data matches the lower half of the IPv6 sender address. Drop silently
916 * if this is not the case. TODO: or send ICMP?
918 void handle_4to6_plain (ssize_t v4datalen, struct sockaddr_in *sin) {
920 // Send the unwrapped IPv6 message out over v6sox
922 v4ether.h_proto = htons (ETH_P_IPV6);
923 memcpy (v4ether.h_dest, v6lladdr, 6);
924 v4ether.h_source [0] = ntohs (sin->sin_port) & 0xff;
925 v4ether.h_source [1] = ntohs (sin->sin_port) >> 8;
926 memcpy (v4ether.h_source + 2, &sin->sin_addr, 4);
928 syslog (LOG_INFO, "Writing IPv6, result = %zd\n",
929 write (v6sox, &v4data6, HDR_SIZE + v4datalen)
935 /* Handle the IPv4 message pointed at by msg as a neighbouring command.
937 * Type Code ICMPv6 meaning Handling
938 * ---- ---- ----------------------------- ----------------------------
939 * 133 0 Router Solicitation Ignore
940 * 134 0 Router Advertisement Setup Tunnel with Prefix
941 * 135 0 Neighbour Solicitation Send Neighbour Advertisement
942 * 136 0 Neighbour Advertisement Ignore
943 * 137 0 Redirect Ignore
945 void handle_4to6_nd (struct sockaddr_in *sin, ssize_t v4ngbcmdlen) {
946 uint16_t srclinklayer;
947 uint8_t *destprefix = NULL;
948 #ifdef TODO_DEPRECATED
949 uint8_t *destlladdr = NULL;
952 if (v4ngbcmdlen < sizeof (struct ip6_hdr) + sizeof (struct icmp6_hdr)) {
956 if (v4v6icmpcode != 0) {
959 if (icmp6_checksum (v4data, v4ngbcmdlen - sizeof (struct ip6_hdr)) != v4v6icmpcksum) {
963 // Approved. Perform neighbourly courtesy.
964 switch (v4v6icmptype) {
965 case ND_ROUTER_SOLICIT:
966 return; /* this is not a router, drop */
967 case ND_ROUTER_ADVERT:
969 // Validate Router Advertisement
970 if (ntohs (v4v6plen) < sizeof (struct icmp6_hdr) + 16) {
971 return; /* strange length, drop */
973 if (v4v6icmpdata [1] & 0x80 != 0x00) {
974 return; /* indecent proposal to use DHCPv6, drop */
976 if (memcmp (&v4src6->s6_addr, router_linklocal_address, 16) != 0) {
977 return; /* not from router, drop */
979 if (memcmp (&v4dst6->s6_addr, client1_linklocal_address, 8) != 0) {
980 if (memcmp (&v4dst6->s6_addr, allnodes_linklocal_address, 16) != 0) {
981 return; /* no address setup for me, drop */
984 if (v4dst6->s6_addr [8] & 0x01) {
985 syslog (LOG_WARNING, "TODO: Ignoring (by accepting) an odd public UDP port revealed in a Router Advertisement -- this could cause confusion with multicast traffic\n");
988 // Parse the Router Advertisement
990 int v6route_count_old = v6route_count;
991 //TODO:+4_WRONG?// while (rdofs <= ntohs (v4v6plen) + 4) { ... }
992 while (rdofs + 4 < ntohs (v4v6plen)) {
993 if (v4v6icmpdata [rdofs + 1] == 0) {
994 return; /* zero length option */
996 #ifdef TODO_DEPRACATED
997 if ((v4v6icmpdata [rdofs + 0] == ND_OPT_DESTINATION_LINKADDR) && (v4v6icmpdata [rdofs + 1] == 1)) {
998 if (v4v6icmpdata [rdofs + 2] & 0x01) {
999 syslog (LOG_WARNING, "TODO: Ignoring an odd UDP port offered in a Router Advertisement over 6bed4\n");
1001 syslog (LOG_INFO, "TODO: Set tunnel link-local address to %02x:%02x:%02x:%02x:%02x:%02x\n", v4v6icmpdata [rdofs + 2], v4v6icmpdata [rdofs + 3], v4v6icmpdata [rdofs + 4], v4v6icmpdata [rdofs + 5], v4v6icmpdata [rdofs + 6], v4v6icmpdata [rdofs + 7]);
1002 destlladdr = &v4v6icmpdata [rdofs + 2];
1003 /* continue with next option */
1006 if (v4v6icmpdata [rdofs + 0] != ND_OPT_PREFIX_INFORMATION) {
1007 /* skip to next option */
1008 } else if (v4v6icmpdata [rdofs + 1] != 4) {
1009 return; /* bad length field */
1010 } else if (rdofs + (v4v6icmpdata [rdofs + 1] << 3) > ntohs (v4v6plen) + 4) {
1011 return; /* out of packet length */
1012 } else if ((v4v6icmpdata [rdofs + 3] & 0xc0) != 0xc0) {
1013 /* no on-link autoconfig, but routable prefix */
1014 printf ("Received a routable prefix %x%02x:%x%02x:%x%02x:%x%02x:.../%d\n", v4v6icmpdata [rdofs+16], v4v6icmpdata [rdofs+17], v4v6icmpdata [rdofs+18], v4v6icmpdata [rdofs+19], v4v6icmpdata [rdofs+20], v4v6icmpdata [rdofs+21], v4v6icmpdata [rdofs+22], v4v6icmpdata [rdofs+22], v4v6icmpdata [rdofs+2]);
1015 if (v6route_count_old > 0) {
1016 v6route_count = v6route_count_old = 0;
1018 if ((v6route_count < MAX_ROUTABLE_PREFIXES) &&
1019 (v4v6icmpdata [rdofs + 2] <= 128) &&
1020 (v4v6icmpdata [rdofs + 2] >= 16)) {
1022 v6route_addr [v6route_count].s6_addr,
1023 &v4v6icmpdata [rdofs+16],
1025 v6route_pfix [v6route_count] =
1026 v4v6icmpdata [rdofs + 2];
1029 } else if (v4v6icmpdata [rdofs + 2] != PREFIX_SIZE) {
1030 /* not a /114 prefix, so no 6bed4 offer */
1033 destprefix = &v4v6icmpdata [rdofs + 16];
1035 rdofs += (v4v6icmpdata [rdofs + 1] << 3);
1038 if (v6route_count_old > 0) {
1041 memcpy (v6listen.s6_addr + 0, destprefix, 16);
1042 v6listen.s6_addr [14] &= 0xc0;
1043 v6listen.s6_addr [15] = 0x01; // choose client 1
1044 memcpy (v6listen_linklocal_complete + 0, v6listen_linklocal, 8);
1045 memcpy (v6listen_linklocal_complete + 8, v6listen.s6_addr + 8, 8);
1046 memcpy (v6lladdr, destprefix + 8, 6);
1047 //TODO// Is v6lladdr useful? Should it include lanip?
1048 v6lladdr [0] &= 0xfc;
1049 v6lladdr [0] |= (destprefix [14] >> 6);
1050 inet_ntop (AF_INET6,
1054 syslog (LOG_INFO, "%s: Assigning address %s to tunnel\n", program, v6prefix);
1055 setup_tunnel_address (); //TODO// parameters?
1057 maintenance_time_cycle = maintenance_time_cycle_max;
1058 maintenance_time_sec = time (NULL) + maintenance_time_cycle;
1059 struct in6_addr start, end;
1060 memcpy (&start, destprefix, 16);
1061 memcpy (&end, destprefix, 16);
1062 start.s6_addr [15] |= 0x02;
1063 end .s6_addr [14] |= 0x3f;
1064 end .s6_addr [15] |= 0xff;
1065 /* Update the extension hooks */
1066 exthook_del_offers ();
1067 exthook_add_range_offer (&start, &end);
1068 for (int i = 0; i < v6route_count; i++) {
1069 exthook_add_route_offer (
1072 (struct in6_addr *) destprefix);
1076 case ND_NEIGHBOR_SOLICIT:
1078 // Validate Neigbour Solicitation (trivial)
1080 // Replicate the message over the IPv6 Link (like plain IPv6)
1081 if (v4ngbcmdlen < 24) {
1082 return; /* too short, drop */
1084 syslog (LOG_DEBUG, "%s: Replicating Neighbor Solicatation from 6bed4 to the IPv6 Link\n", program);
1085 char buf [INET6_ADDRSTRLEN]; uint8_t ll [6]; if ((memcmp (v4src6, v6listen_linklocal, 8) != 0) && (memcmp (v4src6, &v6listen, 8) != 0)) { inet_ntop (AF_INET6, v4src6, buf, sizeof (buf)); syslog (LOG_DEBUG, "Source IPv6 address %s from wrong origin\n", buf); } else { uint8_t pfaddr [16]; memcpy (pfaddr, v6listen.s6_addr, 8); memcpy (pfaddr + 8, v4src6->s6_addr + 8, 8); inet_ntop (AF_INET6, pfaddr, buf, sizeof (buf)); if (lookup_neighbor (pfaddr, ll)) { syslog (LOG_DEBUG, "Source IPv6 %s has Link-Local Address %02x:%02x:%02x:%02x:%02x:%02x with metric %d\n", buf, ll [0], ll [1], ll [2], ll [3], ll [4], ll [5], lladdr_metric (ll)); } else { syslog (LOG_DEBUG, "Source IPv6 %s is unknown to me\n", buf); } }
1086 uint8_t optofs = 4 + 16;
1088 uint8_t *srcll = NULL; /* TODO -- use 6bed4 Network sender instead! */
1089 while ((40 + 4 + optofs + 2 < v4ngbcmdlen) && (40 + 4 + optofs + 8 * v4v6icmpdata [optofs + 1] <= v4ngbcmdlen)) {
1090 if (v4v6icmpdata [optofs] == 1) {
1091 srcll = v4v6icmpdata + optofs + 2;
1093 optofs += 8 * v4v6icmpdata [optofs + 1];
1095 if (srcll) { syslog (LOG_DEBUG, "ND-contained Source Link-Layer Address %02x:%02x:%02x:%02x:%02x:%02x has metric %d\n", srcll [0], srcll [1], srcll [2], srcll [3], srcll [4], srcll [5], lladdr_metric (srcll)); }
1098 // We should attach a Source Link-Layer Address, but
1099 // we cannot automatically trust the one provided remotely.
1100 // Also, we want to detect if routes differ, and handle it.
1102 // 0. if no entry in the ngb.cache
1103 // then use 6bed4 server in ND, initiate ngb.sol to src.ll
1104 // impl: use 6bed4-server lladdr, set highest metric
1105 // 1. if metric (ngb.cache) < metric (src.ll)
1106 // then retain ngb.cache, send Redirect to source
1107 // 2. if metric (ngb.cache) > metric (src.ll)
1108 // then retain ngb.cache, initiate ngb.sol to src.ll
1109 // 3. if metric (ngb.cache) == metric (src.ll)
1110 // then retain ngb.cache
1112 uint8_t src_lladdr [6];
1113 src_lladdr [0] = ntohs (v4name.sin_port) & 0x00ff;
1114 src_lladdr [1] = ntohs (v4name.sin_port) >> 8;
1115 memcpy (src_lladdr + 2, &v4name.sin_addr, 4);
1116 metric_t src_metric = lladdr_metric (src_lladdr);
1117 v4v6icmpdata [4+16+0] = 1; /* Option: Source LLaddr */
1118 v4v6icmpdata [4+16+1] = 1; /* Length: 1x 8 bytes */
1119 uint8_t *ngbc_lladdr = v4v6icmpdata + 4+16+2;
1120 uint8_t ngbc_ipv6 [16];
1121 if (memcmp (v4src6, v6listen_linklocal, 8)) {
1122 memcpy (ngbc_ipv6 + 0, &v6listen, 8);
1123 memcpy (ngbc_ipv6 + 8, v4src6 + 8, 8);
1125 memcpy (ngbc_ipv6, v4src6, 16);
1127 bool ngbc_cached = lookup_neighbor (ngbc_ipv6, ngbc_lladdr);
1128 metric_t ngbc_metric;
1130 ngbc_metric = lladdr_metric (ngbc_lladdr);
1132 ngbc_metric = METRIC_HIGH; /* trigger local ngbsol */
1133 memcpy (ngbc_lladdr, SERVER_6BED4_PORT_IPV4_MACSTR, 6);
1134 syslog (LOG_DEBUG, "Failed to find neighbor in cache, initialising it with the high metric\n");
1136 syslog (LOG_DEBUG, "Metric analysis: source lladdr %02x:%02x:%02x:%02x:%02x:%02x metric %d, neighbor cache lladdr %02x:%02x:%02x:%02x:%02x:%02x metric %d\n", src_lladdr [0], src_lladdr [1], src_lladdr [2], src_lladdr [3], src_lladdr [4], src_lladdr [5], src_metric, ngbc_lladdr [0], ngbc_lladdr [1], ngbc_lladdr [2], ngbc_lladdr [3], ngbc_lladdr [4], ngbc_lladdr [5], ngbc_metric);
1138 // Replicate the ngb.sol with the selected ngbc-lladdr
1139 v4v6icmpcksum = icmp6_checksum ((uint8_t *) v4hdr6, 8 + 16 + 8);
1140 handle_4to6_plain (40 + 24 + 8, &v4name);
1142 // If needed, initiate Neigbor Solicitation to the source
1143 // Note: Also when !ngbc_cached as the router is then cached
1144 if (ngbc_metric > src_metric) {
1145 syslog (LOG_DEBUG, "Trying to find the more direct route that the remote peer seems to be using\n");
1146 enqueue ((struct in6_addr *) v4src6, &v6listen, v6lladdr);
1149 // If needed, ask the source to redo Neighbor Solicitation
1150 if (ngbc_metric < src_metric) {
1151 syslog (LOG_DEBUG, "Redirecting the remote peer to the more efficient route that I am using\n");
1152 redirect_reply (ngbc_lladdr, ngbc_metric);
1155 case ND_NEIGHBOR_ADVERT:
1157 // Process Neighbor Advertisement coming in over 6bed4
1158 // First, make sure it is against an item in the ndqueue
1159 ndq = findqueue ((struct in6_addr *) v4v6ndtarget);
1161 // Ignore advertisement -- it may be an attack
1164 // Remove the matching item from the ndqueue
1166 // Replicate the Neigbor Advertisement over the IPv6 Link (like plain IPv6)
1167 v4v6icmpdata [0] |= 0xe0; /* Router, Solicited, Override */
1168 v4v6icmpdata [20] = 2; /* Target Link-Layer Address */
1169 v4v6icmpdata [21] = 1; /* Length: 1x 8 bytes */
1170 v4v6icmpdata [22] = ntohs (v4name.sin_port) & 0xff;
1171 v4v6icmpdata [23] = ntohs (v4name.sin_port) >> 8;
1172 memcpy (v4v6icmpdata + 24, &v4name.sin_addr, 4);
1173 v4v6plen = htons (24 + 8);
1174 v4v6icmpcksum = icmp6_checksum ((uint8_t *) v4hdr6, 24 + 8);
1175 handle_4to6_plain (sizeof (struct ip6_hdr) + 24 + 8, &v4name);
1179 // Redirect indicates that a more efficient bypass exists than
1180 // the currently used route. The remote peer has established
1181 // this and wants to share that information to retain a
1182 // symmetric communication, which is helpful in keeping holes
1183 // in NAT and firewalls open.
1185 //TODO// BE EXTREMELY SELECTIVE BEFORE ACCEPTING REDIRECT!!!
1186 //TODO:NOTYET// enqueue ((struct in6_addr *) v4v6ndtarget, &v6listen, v6lladdr);
1192 /* Receive a tunnel package, and route it to either the handler for the
1193 * tunnel protocol, or to the handler that checks and then unpacks the
1196 void handle_4to6 (int v4in) {
1199 socklen_t adrlen = sizeof (v4name);
1201 // Receive IPv4 package, which may be tunneled or a tunnel request
1202 buflen = recvfrom (v4in,
1205 (struct sockaddr *) &v4name, &adrlen
1208 syslog (LOG_INFO, "%s: WARNING: Error receiving IPv4-side package: %s\n",
1209 program, strerror (errno));
1210 return; /* receiving error, drop */
1212 if (buflen <= sizeof (struct ip6_hdr)) {
1213 return; /* received too little data, drop */
1215 if ((v4data [0] & 0xf0) != 0x60) {
1216 return; /* not an IPv6 packet, drop */
1218 if (!validate_originator (v4src6)) {
1219 return; /* source appears fake, drop */
1222 * Distinguish types of traffic:
1223 * Non-plain, Plain Unicast, Plain Multicast
1225 if ((v4v6nexthdr == IPPROTO_ICMPV6) &&
1226 (v4v6icmptype >= 133) && (v4v6icmptype <= 137)) {
1228 // Not Plain: Router Adv/Sol, Neighbor Adv/Sol, Redirect
1229 if (v4v6hoplimit != 255) {
1232 handle_4to6_nd (&v4name, buflen);
1235 // Plain Unicast or Plain Multicast (both may enter)
1236 if (v4v6hoplimit-- <= 1) {
1239 handle_4to6_plain (buflen, &v4name);
1245 * Relay an IPv6 package to 6bed4, using the link-local address as it
1246 * is found in the Ethernet header. Trust the local IPv6 stack to have
1247 * properly obtained this destination address through Neighbor Discovery
1250 void handle_6to4_plain_unicast (const ssize_t pktlen, const uint8_t *lladdr) {
1251 struct sockaddr_in v4dest;
1252 memset (&v4dest, 0, sizeof (v4dest));
1253 v4dest.sin_family = AF_INET;
1254 v4dest.sin_port = htons (lladdr [0] | (lladdr [1] << 8));
1255 memcpy (&v4dest.sin_addr, lladdr + 2, 4);
1256 if (v6tc != (v6hdr6->ip6_vfc & htonl (0x0ff00000))) {
1257 v6tc = v6hdr6->ip6_vfc & htonl (0x0ff00000);
1258 v4qos = (ntohl (v6hdr6->ip6_vfc) & 0x0ff00000) >> 24;
1259 if (setsockopt (v4sox, IPPROTO_IP, IP_TOS, &v4qos, sizeof (v4qos)) == -1) {
1260 syslog (LOG_ERR, "Failed to switch IPv4 socket to QoS setting 0x%02x\n", v4qos);
1263 syslog (LOG_DEBUG, "%s: Sending IPv6-UDP-IPv4 to %d.%d.%d.%d:%d, result = %zd\n", program,
1264 ((uint8_t *) &v4dest.sin_addr.s_addr) [0],
1265 ((uint8_t *) &v4dest.sin_addr.s_addr) [1],
1266 ((uint8_t *) &v4dest.sin_addr.s_addr) [2],
1267 ((uint8_t *) &v4dest.sin_addr.s_addr) [3],
1268 ntohs (v4dest.sin_port),
1273 (struct sockaddr *) &v4dest,
1274 sizeof (struct sockaddr_in))
1281 * Handle a request for Neighbor Discovery over the 6bed4 Link.
1283 void handle_6to4_nd (ssize_t pktlen) {
1286 // Validate ICMPv6 message -- trivial, trust local generation
1288 // Handle the message dependent on its type
1289 switch (v6icmp6type) {
1290 case ND_ROUTER_SOLICIT:
1291 v6icmp6type = ND_ROUTER_ADVERT;
1293 v6icmp6data [0] = 0; // Cur Hop Limit: unspec
1294 v6icmp6data [1] = 0x18; // M=0, O=0,
1297 //TODO: wire says 0x44 for router_adv.flags
1298 size_t writepos = 2;
1299 memset (v6icmp6data + writepos,
1300 default_route? 0xff: 0x00,
1301 2); // Router Lifetime
1303 memcpy (v6icmp6data + writepos,
1305 4); // Reachable Time: 32s
1307 memcpy (v6icmp6data + writepos,
1309 4); // Retrans Timer: .25s
1311 writepos = icmp6_prefix (writepos, 0);
1312 v6plen = htons (4 + writepos);
1313 memcpy (v6dst6, v6src6, 16);
1314 memcpy (v6src6, v6listen_linklocal_complete, 16);
1315 v6icmp6csum = icmp6_checksum ((uint8_t *) v6hdr6, 4 + writepos);
1317 v6ether.h_proto = htons (ETH_P_IPV6);
1318 memcpy (v6ether.h_dest, v6ether.h_source, 6);
1319 memcpy (v6ether.h_source, v6lladdr, 6);
1321 syslog (LOG_INFO, "Replying Router Advertisement to the IPv6 Link, result = %zd\n",
1322 write (v6sox, &v6data6, HDR_SIZE + sizeof (struct ip6_hdr) + 4 + writepos)
1326 case ND_ROUTER_ADVERT:
1327 return; /* the IPv6 Link is no router, drop */
1328 case ND_NEIGHBOR_SOLICIT:
1330 // Neighbor Solicitation is treated depending on its kind:
1331 // - the 6bed4 Router address is answered immediately
1332 // - discovery for the local IPv6 address is dropped
1333 // - discovery for fe80::/64 addresses is answered
1334 // - other peers start a process in the ndqueue
1335 if ((memcmp (v6ndtarget, router_linklocal_address, 16) == 0) ||
1336 (memcmp (v6ndtarget, router_linklocal_address_complete, 16) == 0)) {
1337 advertise_6bed4_public_service (NULL);
1338 } else if (memcmp (v6ndtarget, &v6listen, 16) == 0) {
1339 return; /* yes you are unique, drop */
1340 } else if (memcmp (v6ndtarget, v6listen_linklocal, 8) == 0) {
1342 // Construct response for fe80::/64
1343 v6icmp6type = ND_NEIGHBOR_ADVERT;
1344 v6icmp6data [0] = 0x60; /* Solicited, Override */
1345 v6icmp6data [20] = 2; /* Target Link-Layer Address */
1346 v6icmp6data [21] = 1; /* Length is 1x 8 bytes */
1347 v6icmp6data [22] = v6icmp6data [12] ^ 0x02;
1348 v6icmp6data [23] = v6icmp6data [13];
1349 v6icmp6data [24] = v6icmp6data [14];
1350 v6icmp6data [25] = v6icmp6data [17];
1351 v6icmp6data [26] = v6icmp6data [18];
1352 v6icmp6data [27] = v6icmp6data [19];
1353 v6plen = htons (4 + 28);
1354 memcpy (v6dst6, v6src6, 16);
1355 memcpy (v6src6, &v6listen, 16);
1357 memcpy (v6ether.h_dest, v6ether.h_source, 6);
1358 memcpy (v6ether.h_source, v6lladdr, 6);
1360 v6icmp6csum = icmp6_checksum ((uint8_t *) v6hdr6, 4 + 28);
1361 syslog (LOG_DEBUG, "Sending trivial reply to fe80::/64 type query\n");
1362 write (v6sox, &v6data6, HDR_SIZE + sizeof (struct ip6_hdr) + 4 + 28);
1367 enqueue ((struct in6_addr *) v6ndtarget, (struct in6_addr *) v6src6, v6ether.h_source);
1371 case ND_NEIGHBOR_ADVERT:
1372 lldest [0] = v6dst6->s6_addr [8] ^ 0x02;
1373 lldest [1] = v6dst6->s6_addr [9];
1374 lldest [2] = v6dst6->s6_addr [10];
1375 lldest [3] = v6dst6->s6_addr [13];
1376 lldest [4] = v6dst6->s6_addr [14];
1377 lldest [5] = v6dst6->s6_addr [15];
1378 handle_6to4_plain_unicast (pktlen, lldest);
1381 //TODO:NOT_IMPLEMENTED_YET:ND_REDIRECT_FROM_6BED4//
1383 // Redirect indicates that a more efficient bypass exists than
1384 // the currently used route. The remote peer has established
1385 // this and wants to share that information to retain a
1386 // symmetric communication, which is helpful in keeping holes
1387 // in NAT and firewalls open.
1394 * Receive an IPv6 package, check its address and pickup IPv4 address and
1395 * port, then package it as a tunnel message and forward it to IPv4:port.
1396 * Rely on the proper formatting of the incoming IPv6 packet, as it is
1397 * locally generated.
1399 void handle_6to4 (void) {
1400 #ifndef PEER_USE_TAP
1401 static uint8_t lladdr [] =
1404 UDP_PORT_6BED4 & 0xff,
1405 UDP_PORT_6BED4 >> 8,
1407 SERVER_6BED4_IPV4_INT0,
1408 SERVER_6BED4_IPV4_INT1,
1409 SERVER_6BED4_IPV4_INT2,
1410 SERVER_6BED4_IPV4_INT3
1414 // Receive the IPv6 package and ensure a consistent size
1415 size_t rawlen = read (v6sox, &v6data6, sizeof (v6data6));
1417 return; /* failure to read, drop */
1419 if (rawlen < HDR_SIZE + sizeof (struct ip6_hdr) + 1) {
1420 return; /* packet too small, drop */
1423 if (v6ether.h_proto != htons (ETH_P_IPV6)) {
1424 return; /* not IPv6, drop */
1426 //TODO// syslog (LOG_DEBUG, "Packet from IPv6 stack, target %02x:%02x:%02x:%02x:%02x:%02x\n", v6ether.h_dest [0], v6ether.h_dest [1], v6ether.h_dest [2], v6ether.h_dest [3], v6ether.h_dest [4], v6ether.h_dest [5]);
1428 // Ignore messages from the IPv6 stack to itself
1429 if (memcmp (v6ether.h_dest, v6ether.h_source, 6) == 0) {
1430 syslog (LOG_DEBUG, "TODO: Self-to-self messaging in IPv6 stack ignored\n");
1435 * Distinguish types of traffic:
1436 * Non-plain, Plain Unicast, Plain Multicast
1438 if ((v6type == IPPROTO_ICMPV6) &&
1439 (v6icmp6type >= 133) && (v6icmp6type <= 137)) {
1441 // Not Plain: Router Adv/Sol, Neighbor Adv/Sol, Redirect
1442 syslog (LOG_DEBUG, "Forwarding non-plain unicast from IPv6 to 6bed4\n");
1443 handle_6to4_nd (rawlen);
1444 } else if ((v6dst6->s6_addr [0] != 0xff) && !(v6dst6->s6_addr [8] & 0x01)) {
1447 if (v6hops-- <= 1) {
1450 syslog (LOG_DEBUG, "Forwarding plain unicast from IPv6 to 6bed4\n");
1452 handle_6to4_plain_unicast (rawlen, v6ether.h_dest);
1454 handle_6to4_plain_unicast (rawlen, lladdr);
1460 //TODO:IGNORE_MULTICAST//
1461 //TODO// syslog (LOG_DEBUG, "%s: Plain multicast from 6bed4 Link to 6bed4 Network is not supported\n", program);
1467 * Send a single Neighbor Solicitation message over 6bed4. This will
1468 * be sent to the given 6bed4 address, and is usually part of a series
1469 * of attempts to find a short-cut route to the 6bed4 peer.
1471 void solicit_6bed4_neighbor (const struct ndqueue *info, const uint8_t *addr6bed4) {
1472 memcpy (v6src6, &info->source, 16);
1473 memcpy (v6dst6, &info->target, 16);
1474 v6type = IPPROTO_ICMPV6;
1476 v6icmp6type = ND_NEIGHBOR_SOLICIT;
1481 v6icmp6data [3] = 0x00;
1482 memcpy (v6icmp6data + 4, &info->target, 16);
1483 v6icmp6data [20] = 1; // option type is Source Link-Layer Address
1484 v6icmp6data [21] = 1; // option length is 1x 8 bytes
1485 memcpy (v6icmp6data + 22, v6lladdr, 6);
1486 uint16_t pktlen = sizeof (struct ip6_hdr) + 4 + 28;
1487 //OLD// v6icmp6csum = icmp6_checksum ((uint8_t *) v6hdr6, 28 + 8);
1488 v6plen = htons (4 + 28);
1489 v6icmp6csum = icmp6_checksum ((uint8_t *) v6hdr6, 4 + 28);
1490 handle_6to4_plain_unicast (sizeof (struct ip6_hdr) + 8 + 28 + 10, addr6bed4);
1491 //TODO// Why these +8 and +10 are needed, I don't know yet!
1496 * Find a neighbor's 6bed4 address. This is coordinated by the ndqueue,
1497 * which schedules such tasks and makes them repeat. Furthermore, a few
1498 * attempts may be scheduled on the local network before attempts
1499 * shift to the direct target IPv4/UDP addresses. Of course the local
1500 * network will only be scheduled if the public IPv4 address matches
1501 * the one for the local node.
1503 * This process is dequeued by reverse Neighbor Advertisements. If none
1504 * comes back in spite of the various Neighbor Solicitations sent, then
1505 * the final action is to send a Neighbor Advertisement to the host with
1506 * the Public 6bed4 Service as its target of last resort. In case of
1507 * this last resort, the process is not continued any further; the
1508 * return value indicates whether the queue entry should be kept for
1511 bool chase_neighbor_6bed4_address (struct ndqueue *info) {
1512 uint8_t addr6bed4 [6];
1513 static const uint8_t addr6bed4_lancast [8] = {
1514 UDP_PORT_6BED4 & 0xff, UDP_PORT_6BED4 >> 8,
1517 if (info->todo_lancast > 0) {
1518 // Attempt 1. Send to LAN multicast address (same public IP)
1519 info->todo_lancast--;
1520 solicit_6bed4_neighbor (info, addr6bed4_lancast);
1522 } else if (info->todo_direct > 0) {
1523 // Attempt 2. Send to target's direct IP address / UDP port
1524 info->todo_direct--;
1525 addr6bed4 [0] = info->target.s6_addr [8] ^ 0x02;
1526 addr6bed4 [1] = info->target.s6_addr [9];
1527 addr6bed4 [2] = info->target.s6_addr [10];
1528 addr6bed4 [3] = info->target.s6_addr [13];
1529 addr6bed4 [4] = info->target.s6_addr [14];
1530 addr6bed4 [5] = info->target.s6_addr [15];
1531 solicit_6bed4_neighbor (info, addr6bed4);
1534 // Attempt 3. Respond with Public 6bed4 Service
1535 syslog (LOG_INFO, "%s: Failed to find a bypass, passing back the 6bed4 Router\n", program);
1536 advertise_6bed4_public_service (info);
1543 * Perform Router Solicitation. This is the usual mechanism that is used
1544 * on ethernet links as well, except that the 6bed4 permits fixed interface
1545 * identifiers; for this client, the interface identifier will be 0x0001.
1546 * The router always has interface identifier 0x0000 but it will now be
1547 * addressed at the all-routers IPv6 address 0xff02::2 with the general
1548 * source IPv6 address ::
1550 void solicit_router (void) {
1551 v4name.sin_family = AF_INET;
1552 memcpy (&v4name.sin_addr.s_addr, &v4listen, 4);
1553 v4name.sin_port = htons (UDP_PORT_6BED4);
1556 // syslog (LOG_DEBUG, "%s: Sending RouterSolicitation-IPv6-UDP-IPv4 to %d.%d.%d.%d:%d, result = %d\n", program,
1557 // ((uint8_t *) &v4name.sin_addr.s_addr) [0],
1558 // ((uint8_t *) &v4name.sin_addr.s_addr) [1],
1559 // ((uint8_t *) &v4name.sin_addr.s_addr) [2],
1560 // ((uint8_t *) &v4name.sin_addr.s_addr) [3],
1561 // ntohs (v4name.sin_port),
1564 ipv6_router_solicitation,
1565 sizeof (ipv6_router_solicitation),
1567 (struct sockaddr *) &v4name, sizeof (v4name)));
1572 * Send a KeepAlive message. This is an UDP/IPv4 message with no contents.
1573 * The router will not respond, but that is okay; outgoing traffic is the
1574 * way to keep holes in NAT and firewalls open.
1576 void keepalive (void) {
1577 v4name.sin_family = AF_INET;
1578 memcpy (&v4name.sin_addr.s_addr, &v4listen, 4);
1579 v4name.sin_port = htons (UDP_PORT_6BED4);
1582 setsockopt (v4sox, IPPROTO_IP, IP_TTL, &keepalive_ttl, sizeof (keepalive_ttl));
1587 (struct sockaddr *) &v4name, sizeof (v4name));
1588 setsockopt (v4sox, IPPROTO_IP, IP_TTL, &v4ttl, sizeof (v4ttl));
1592 /* Regular maintenance is a routine that runs regularly to do one of two
1593 * generic tasks: either it sends Router Solicitation messages to the
1594 * Public 6bed4 Service, or it sends an empty UDP message somewhat in its
1595 * direction to keep NAT/firewall holes open.
1597 void regular_maintenance (void) {
1600 maintenance_time_cycle <<= 1;
1601 maintenance_time_cycle += 1;
1602 if (maintenance_time_cycle > maintenance_time_cycle_max) {
1603 maintenance_time_cycle = maintenance_time_cycle_max;
1605 syslog (LOG_INFO, "Sent Router Advertisement to Public 6bed4 Service, next attempt in %ld seconds\n", maintenance_time_cycle);
1607 syslog (LOG_INFO, "Sending a KeepAlive message (empty UDP) to the 6bed4 Router\n");
1609 maintenance_time_cycle = maintenance_time_cycle_max;
1611 maintenance_time_sec = time (NULL) + maintenance_time_cycle;
1615 /* Indicate that the running daemon should stop. This is intended as a
1616 * signal handler function, and would instruct the select() loop to
1619 void signal_daemon (int signum) {
1624 /* Run the daemon core code, passing information between IPv4 and IPv6 and
1625 * responding to tunnel requests if so requested. The loop ends when a
1626 * suitable signal is received: HUP, INT, KILL, TERM.
1628 void run_daemon (void) {
1629 atexit (exthook_del_offers);
1632 maintenance_time_sec = 0; // trigger Router Solicitation
1633 signal (SIGHUP, signal_daemon);
1634 signal (SIGINT, signal_daemon);
1635 signal (SIGKILL, signal_daemon);
1636 signal (SIGTERM, signal_daemon);
1638 FD_SET (v4sox, &io);
1639 FD_SET (v6sox, &io);
1640 int nfds = (v4sox < v6sox)? (v6sox + 1): (v4sox + 1);
1641 if (v4mcast != -1) {
1642 FD_SET (v4mcast, &io);
1643 if (v4mcast >= nfds) {
1647 while (signalnum == 0) {
1648 struct timeval tout;
1650 gettimeofday (&now, NULL);
1651 if (maintenance_time_sec <= now.tv_sec) {
1652 regular_maintenance ();
1654 tout.tv_sec = maintenance_time_sec - now.tv_sec;
1657 ((ndqueue->next->tv.tv_sec == now.tv_sec)
1658 && (ndqueue->next->tv.tv_usec <= now.tv_usec))
1659 || (ndqueue->next->tv.tv_sec < now.tv_sec))) {
1661 // Run the entry's handler code
1662 syslog (LOG_DEBUG, "Queue at %ld.%03ld: Timed for %ld.%03ld", now.tv_sec, now.tv_usec / 1000, ndqueue->next->tv.tv_sec, ndqueue->next->tv.tv_usec / 1000);
1663 keep = chase_neighbor_6bed4_address (ndqueue->next);
1665 dequeue (ndqueue->next);
1669 // Make ndqueue point to the entry to run
1670 ndqueue = ndqueue->next;
1672 // Add 50ms to the running time
1673 if (now.tv_usec < 950000) {
1674 ndqueue->tv.tv_usec = now.tv_usec + 50000;
1675 ndqueue->tv.tv_sec = now.tv_sec + 0;
1677 ndqueue->tv.tv_usec = now.tv_usec - 950000;
1678 ndqueue->tv.tv_sec = now.tv_sec + 1;
1681 if (ndqueue && ((ndqueue->next->tv.tv_sec - now.tv_sec) < tout.tv_sec)) {
1682 tout.tv_sec = ndqueue->next->tv.tv_sec - now.tv_sec ;
1683 tout.tv_usec = ndqueue->next->tv.tv_usec - now.tv_usec;
1684 if (tout.tv_usec < 0) {
1685 tout.tv_usec += 1000000;
1689 if (select (nfds, &io, NULL, NULL, &tout) < 0) {
1690 if (errno == EINTR) {
1693 syslog (LOG_ERR, "Select failed: %s\n", strerror (errno));
1695 if (FD_ISSET (v4sox, &io)) {
1696 syslog (LOG_DEBUG, "Got unicast input\n");
1697 handle_4to6 (v4sox);
1699 FD_SET (v4sox, &io);
1701 if (FD_ISSET (v6sox, &io)) {
1704 FD_SET (v6sox, &io);
1706 if (v4mcast != -1) {
1707 if (FD_ISSET (v4mcast, &io)) {
1708 syslog (LOG_DEBUG, "WOW: Got multicast input\n");
1709 handle_4to6 (v4mcast);
1711 FD_SET (v4mcast, &io);
1719 /* Option descriptive data structures */
1721 char *short_opt = "s:t:d:l:p:rk:fex:h";
1723 struct option long_opt [] = {
1724 { "v4server", 1, NULL, 's' },
1725 { "tundev", 1, NULL, 'd' },
1726 { "default-route", 0, NULL, 'r' },
1727 { "listen", 1, NULL, 'l' },
1728 { "port", 1, NULL, 'p' },
1729 { "ttl", 1, NULL, 't' },
1730 { "foreground", 0, NULL, 'f' },
1731 { "fork-not", 0, NULL, 'f' },
1732 { "keepalive", 1, NULL, 'k' },
1733 { "keepalive-period-ttl", 1, NULL, 'k' },
1734 { "error-console", 0, NULL, 'e' },
1735 { "extension-hook", 1, NULL, 'x' },
1736 { "help", 0, NULL, 'h' },
1737 { NULL, 0, NULL, 0 } /* Array termination */
1741 /* Parse commandline arguments (and start to process them).
1742 * Return 1 on success, 0 on failure.
1744 int process_args (int argc, char *argv []) {
1748 unsigned long tmpport;
1750 default_route = false;
1752 switch (getopt_long (argc, argv, short_opt, long_opt, NULL)) {
1755 if (optind != argc) {
1756 fprintf (stderr, "%s: Extra arguments not permitted: %s...\n", program, argv [optind]);
1763 fprintf (stderr, "%s: You can only specify a single server address\n", program);
1767 if (inet_pton (AF_INET, optarg, &v4peer.sin_addr) <= 0) {
1769 fprintf (stderr, "%s: Failed to parse IPv4 address %s\n", program, optarg);
1772 memcpy (&v4listen, &v4peer.sin_addr, 4);
1773 v4sox = socket (AF_INET, SOCK_DGRAM, 0);
1776 fprintf (stderr, "%s: Failed to allocate UDPv4 socket: %s\n", program, strerror (errno));
1783 fprintf (stderr, "%s: Multiple -d arguments are not permitted\n", program);
1786 v6sox = open (optarg, O_RDWR);
1789 fprintf (stderr, "%s: Failed to open tunnel device %s: %s\n", program, optarg, strerror (errno));
1794 if (default_route) {
1795 fprintf (stderr, "%s: You can only request default route setup once\n", program);
1799 default_route = true;
1802 if (inet_pton (AF_INET, optarg, &v4bind.sin_addr.s_addr) != 1) {
1803 fprintf (stderr, "%s: IPv4 address %s is not valid\n", program, optarg);
1809 tmpport = strtoul (optarg, &endarg, 10);
1810 if ((*endarg) || (tmpport > 65535)) {
1811 fprintf (stderr, "%s: UDP port number %s is not valid\n", program, optarg);
1815 if (tmpport & 0x0001) {
1816 fprintf (stderr, "%s: UDP port number %ld is odd, which is not permitted\n", program, tmpport);
1820 v4bind.sin_port = htons (tmpport);
1824 fprintf (stderr, "%s: You can only request foreground operation once\n", program);
1831 if (log_to_stderr) {
1832 fprintf (stderr, "%s: You can only specify logging to stderr once\n", program);
1836 log_to_stderr = true;
1839 if (v4ttl_mcast != -1) {
1840 fprintf (stderr, "%s: You can set the ttl for multicast once\n", program);
1845 long setting = strtol(optarg, &zero, 10);
1846 if (*zero || (setting < 0) || (setting > 255)) {
1847 fprintf (stderr, "%s: Multicast radius must be a number in the range 0 to 255, inclusive, not %s\n", program, optarg);
1851 v4ttl_mcast = setting;
1854 if (keepalive_ttl != -1) {
1855 fprintf (stderr, "%s: You can only set the keepalive period and TTL once\n", program);
1860 keepalive_period = strtol (optarg, &rest, 10);
1863 keepalive_ttl = strtol (rest, &rest, 10);
1864 if ((keepalive_ttl < 0) || (keepalive_ttl > 255)) {
1865 fprintf (stderr, "%s: The keepalive TTL must be in the range 0 to 255, inclusive\n", program);
1873 fprintf (stderr, "%s: The format for keepalive configuration is 'period,ttl' or just 'period', but not %s\n", program, optarg);
1878 if (exthook != NULL) {
1879 fprintf (stderr, "%s: You can only specify one extension hook\n", program);
1887 /* continue into 'h' to produce usage information */
1897 #ifdef HAVE_SETUP_TUNNEL
1898 fprintf (stderr, "Usage: %s [-r] [-d /dev/tunX]\n %s -h\n", program, program);
1900 fprintf (stderr, "Usage: %s [-r] -d /dev/tunX\n %s -h\n", program, program);
1907 if (keepalive_ttl != -1) {
1908 maintenance_time_cycle_max = keepalive_period;
1912 #ifdef HAVE_SETUP_TUNNEL
1914 if (geteuid () != 0) {
1915 fprintf (stderr, "%s: You should be root, or use -d to specify an accessible tunnel device\n", program);
1918 ok = setup_tunnel ();
1920 fprintf (stderr, "Failed to setup tunnel\n");
1924 #else /* ! HAVE_SETUP_TUNNEL */
1926 fprintf (stderr, "%s: You must specify a tunnel device with -d that is accessible to you\n", program);
1929 #endif /* HAVE_SETUP_TUNNEL */
1934 /* The main program parses commandline arguments and forks off the daemon
1936 int main (int argc, char *argv []) {
1939 program = strrchr (argv [0], '/');
1945 memset (&v4name, 0, sizeof (v4name));
1946 memset (&v4peer, 0, sizeof (v4peer));
1947 memset (&v6name, 0, sizeof (v6name));
1948 v4name.sin_family = AF_INET ;
1949 v4peer.sin_family = AF_INET ;
1950 v6name.sin6_family = AF_INET6;
1951 // Fixed public server data, IPv4 and UDP:
1952 v4server = SERVER_6BED4_IPV4_TXT;
1953 v4peer.sin_addr.s_addr = htonl (SERVER_6BED4_IPV4_INT32);
1954 v4name.sin_port = htons (UDP_PORT_6BED4);
1955 v4peer.sin_port = htons (UDP_PORT_6BED4);
1956 memcpy (&v4listen, &v4peer.sin_addr, 4);
1957 memset (&v4bind, 0, sizeof (v4bind));
1958 v4bind.sin_family = AF_INET;
1959 #ifndef PEER_USE_TAP
1961 v4tunpi6.proto = htons (ETH_P_IPV6);
1964 // Parse commandline arguments
1965 openlog (program, LOG_NDELAY | LOG_PID | LOG_PERROR, LOG_DAEMON);
1966 if (!process_args (argc, argv)) {
1967 fprintf (stderr, "Argument processing failed\n");
1970 if (!log_to_stderr) {
1972 openlog (program, LOG_NDELAY | LOG_PID, LOG_DAEMON);
1975 // Construct the 6bed4 Router's complete link-layer address
1976 router_linklocal_address_complete [8] = (ntohs (v4peer.sin_port) & 0xff) ^ 0x02;
1977 router_linklocal_address_complete [9] = ntohs (v4peer.sin_port) >> 8;
1978 router_linklocal_address_complete [10] = ntohl (v4peer.sin_addr.s_addr) >> 24;
1979 router_linklocal_address_complete [11] = 0xff;
1980 router_linklocal_address_complete [12] = 0xfe;
1981 memcpy (router_linklocal_address_complete + 13, &((uint8_t *) &v4peer.sin_addr) [1], 3);
1983 // Create memory for the freequeue buffer
1984 freequeue = calloc (freequeue_items, sizeof (struct ndqueue));
1986 syslog (LOG_CRIT, "%s: Failed to allocate %d queue items\n", program, freequeue_items);
1990 for (i = 1; i < freequeue_items; i++) {
1991 freequeue [i].next = &freequeue [i-1];
1993 freequeue = &freequeue [freequeue_items - 1];
1995 // Create socket for normal outgoing (and return) 6bed4 traffic
1997 v4sox = socket (AF_INET, SOCK_DGRAM, 0);
1999 syslog (LOG_CRIT, "%s: Failed to open a local IPv4 socket -- does your system still support IPv4?\n", program);
2003 struct sockaddr_in tmpaddr;
2004 memset (&tmpaddr, 0, sizeof (tmpaddr));
2005 tmpaddr.sin_family = AF_INET;
2007 uint16_t portn = rand () & 0x3ffe;
2008 uint16_t port0 = portn + 16384;
2009 //TODO// Move port iteration + allocation to separate function
2010 while (portn < port0) {
2011 tmpaddr.sin_port = htons ((portn & 0x3ffe) + 49152);
2012 if (bind (v4sox, (struct sockaddr *) &tmpaddr, sizeof (tmpaddr)) == 0) {
2017 if (portn < port0) {
2018 syslog (LOG_DEBUG, "Bound to UDP port %d\n", ntohs (tmpaddr.sin_port));
2020 fprintf (stderr, "%s: All even dynamic ports rejected binding: %s\n", program, strerror (errno));
2024 // Setup fragmentation, QoS and TTL options
2027 #if defined(IP_DONTFRAG)
2028 if (setsockopt (v4sox, IPPROTO_IP, IP_DONTFRAG, no, sizeof (no)) == -1) {
2029 syslog (LOG_ERR, "Failed to permit fragmentation -- not all peers may be accessible with MTU 1280");
2031 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2032 int pmtuflag = IP_PMTUDISC_DONT;
2033 if (setsockopt (v4sox, IP_MTU_DISCOVER, IP_MTU_DISCOVER, &pmtuflag, sizeof (pmtuflag)) == -1) {
2034 syslog (LOG_ERR, "Failed to permit fragmentation -- not all peers may be accessible with MTU 1280");
2037 #warning "Target system lacks support for controlling packet fragmentation"
2039 socklen_t soxlen = sizeof (v4qos);
2040 if (getsockopt (v4sox, IPPROTO_IP, IP_TOS, &v4qos, &soxlen) == -1) {
2041 syslog (LOG_ERR, "Quality of Service is not supported by the IPv4-side socket");
2044 v6tc = htonl (v4qos << 20);
2045 soxlen = sizeof (v4ttl);
2046 if (getsockopt (v4sox, IPPROTO_IP, IP_TTL, &v4ttl, &soxlen) == -1) {
2047 syslog (LOG_ERR, "Time To Live cannot be varied on the IPv4 socket");
2051 // Bind to the IPv4 all-nodes local multicast address
2052 memset (&v4allnodes, 0, sizeof (v4allnodes));
2053 v4allnodes.sin_family = AF_INET;
2054 v4allnodes.sin_port = htons (UDP_PORT_6BED4);
2055 v4allnodes.sin_addr.s_addr = htonl ( INADDR_ANY );
2057 v4mcast = socket (AF_INET, SOCK_DGRAM, 0);
2058 if (v4mcast != -1) {
2059 struct ip_mreq mreq;
2060 mreq.imr_multiaddr.s_addr = htonl ( (224L << 24) | 1L);
2061 mreq.imr_multiaddr.s_addr = htonl ( INADDR_ANY );
2062 if (bind (v4mcast, (struct sockaddr *) &v4allnodes, sizeof (v4allnodes)) != 0) {
2065 syslog (LOG_ERR, "No LAN bypass: Failed to bind to IPv4 all-nodes: %s\n", strerror (errno));
2066 } else if (setsockopt (v4mcast, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (yes)) == -1) {
2069 syslog (LOG_ERR, "No LAN bypass: Failed to share multicast port: %s\n", strerror (errno));
2070 } else if (setsockopt (v4mcast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof (mreq)) == -1) {
2073 syslog (LOG_ERR, "No LAN bypass: Failed to setup multicast: %s\n", strerror (errno));
2074 } else if ((v4ttl_mcast != -1) && (setsockopt (v4mcast, IPPROTO_IP, IP_MULTICAST_TTL, &v4ttl_mcast, sizeof (v4ttl_mcast)) == -1)) {
2077 syslog (LOG_ERR, "No LAN bypass: Failed to configure the multicast radius: %s\n", strerror (errno));
2080 if (bind (v4mcast, (struct sockaddr *) &v4allnodes, sizeof (v4allnodes)) != 0) {
2083 syslog (LOG_ERR, "%s: No LAN bypass: Failed to bind to IPv4 all-nodes\n", program);
2084 } else if (listen (v4mcast, 10) != 0) {
2087 syslog (LOG_ERR, "%s: No LAN bypass: Failed to listen to IPv4 all-nodes\n", program);
2092 syslog (LOG_INFO, "%s: No LAN bypass: Not desired\n", program);
2095 // Construct an rtnetlink socket for neighbor cache interaction
2096 rtsox = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
2098 syslog (LOG_CRIT, "Failed to gain access to the neighbor cache: %s\n", strerror (errno));
2101 memset (&rtname, 0, sizeof (rtname ));
2102 memset (&rtkernel, 0, sizeof (rtkernel));
2103 rtname.nl_family = rtkernel.nl_family = AF_NETLINK;
2104 rtname.nl_pid = getpid ();
2105 if (bind (rtsox, (struct sockaddr *) &rtname, sizeof (rtname)) == -1) {
2106 syslog (LOG_CRIT, "Failed to bind to the neighbor cache socket: %s\n", strerror (errno));
2109 if (connect (rtsox, (struct sockaddr *) &rtkernel, sizeof (rtkernel)) == -1) {
2110 syslog (LOG_CRIT, "Failed to connect to the neighbor cachr in the kernel; %s\n", strerror (errno));
2113 { uint8_t testll [6];
2114 uint8_t test_address [] = { 0xfe, 0x80, 0,0,0,0,0,0, 0xc2, 0x25, 0x06, 0xff, 0xfe, 0xb0, 0x7e, 0xa6 };
2115 if (lookup_neighbor (test_address, testll)) {
2116 syslog (LOG_INFO, "Successfully retrieved LL: %02x:%02x:%02x:%02x:%02x:%02x\n", testll [0], testll [1], testll [2], testll [3], testll [4], testll [5]);
2117 } else { syslog (LOG_INFO, "Failed to find LL\n"); } }
2119 // If port and/or listen arguments were provided, bind to them
2120 if ((v4bind.sin_addr.s_addr != INADDR_ANY) || (v4bind.sin_port != 0)) {
2121 if (bind (v4sox, (struct sockaddr *) &v4bind, sizeof (v4bind)) != 0) {
2122 syslog (LOG_CRIT, "%s: Failed to bind to local socket -- did you specify both address and port?\n", program);
2131 if (setsid () != -1) {
2132 syslog (LOG_CRIT, "%s: Failure to detach from parent session: %s\n", program, strerror (errno));
2137 syslog (LOG_CRIT, "%s: Failure to fork daemon process: %s\n", program, strerror (errno));
2141 if (! log_to_stderr) {
2152 // Report successful creation of the daemon