Migration to GitLab
[6bed4] / src / 6bed4peer.c
1 /* 6bed4/peer.c -- Peer-to-Peer IPv6-anywhere with 6bed4 -- peer.c
2  *
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
6  * distributed widely.
7  *
8  * From: Rick van Rein <rick@openfortress.nl>
9  */
10
11
12 #include <stdlib.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <getopt.h>
20 #include <fcntl.h>
21 #include <time.h>
22
23 #include <signal.h>
24 #include <syslog.h>
25 #ifndef LOG_PERROR
26 #define LOG_PERROR LOG_CONS             /* LOG_PERROR is non-POSIX, LOG_CONS is */
27 #endif
28
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/time.h>
32 #include <sys/select.h>
33 #include <sys/ioctl.h>
34
35 #include <net/if.h>
36
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>
43
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>
50
51 /* The following will initially fail, due to an IANA obligation to avoid
52  * default builds with non-standard options.
53  */
54 #include "nonstd.h"
55
56
57 #define MTU 1280
58 #define PREFIX_SIZE 114
59
60 typedef enum {
61         METRIC_LOW,
62         METRIC_MEDIUM,
63         METRIC_HIGH
64 } metric_t;
65
66 /*
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.
71  */
72 #undef HAVE_SETUP_TUNNEL
73
74
75 #ifndef MAX_ROUTABLE_PREFIXES
76 #define MAX_ROUTABLE_PREFIXES 10
77 #endif
78
79
80 /* Global variables */
81
82 char *program;
83 char *exthook;
84
85 volatile int signalnum = 0;
86
87 int rtsox = -1;
88 int v4sox = -1;
89 int v6sox = -1;
90 int v4mcast = -1;
91
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 */
96
97 char *v4server = NULL;
98 char *v6server = NULL;
99 char v6prefix [INET6_ADDRSTRLEN];
100 uint8_t v6lladdr [6];
101
102 struct in6_addr v6route_addr [MAX_ROUTABLE_PREFIXES];
103 uint8_t         v6route_pfix [MAX_ROUTABLE_PREFIXES];
104 int             v6route_count = 0;
105
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 };
108
109 struct sockaddr_nl rtname;
110 struct sockaddr_nl rtkernel;
111
112 struct sockaddr_in  v4name;
113 struct sockaddr_in  v4peer;
114 struct sockaddr_in6 v6name;
115
116 struct sockaddr_in v4bind;
117 struct sockaddr_in v4allnodes;
118
119 struct in6_addr v6listen;
120 //TODO:NEEDNOT// struct in6_addr v6listen_complete;
121 struct in_addr  v4listen;
122
123
124 struct {
125 #ifdef PEER_USE_TAP
126         struct ethhdr eth;
127 #else
128         struct tun_pi tun;
129 #endif
130         union {
131                 struct {
132                         struct ip6_hdr v6hdr;
133                         uint8_t data [MTU - sizeof (struct ip6_hdr)];
134                 } idata;
135                 struct {
136                         struct ip6_hdr v6hdr;
137                         struct icmp6_hdr v6icmphdr;
138                 } ndata;
139         } udata;
140 } __attribute__((packed)) v4data6;
141
142 #ifdef PEER_USE_TAP
143 #define v4ether         (v4data6.eth)
144 #else
145 #define v4tunpi6        (v4data6.tun)
146 #endif
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)
151
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)
155
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])
162
163
164 struct {
165 #ifdef PEER_USE_TAP
166         struct ethhdr eth;
167 #else
168         struct tun_pi tun;
169 #endif
170         union {
171                 uint8_t data [MTU];
172                 struct {
173                         struct ip6_hdr v6hdr;
174                         struct icmp6_hdr v6icmp;
175                 } __attribute__((packed)) ndata;
176         } udata;
177 }  __attribute__((packed)) v6data6;
178
179 #ifdef PEER_USE_TAP
180 #define v6ether         (v6data6.eth)
181 #else
182 #define v6tuncmd        (v6data6.tun)
183 #endif
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])
196
197 #ifdef PEER_USE_TAP
198 #define HDR_SIZE        (sizeof(struct ethhdr))
199 #else
200 #define HDR_SIZE        (sizeof(struct tun_pi))
201 #endif
202
203 /* Structure for tasks in neighbor discovery queues
204  */
205 struct ndqueue {
206         struct ndqueue *next;
207         struct timeval tv;
208         struct in6_addr source;
209         struct in6_addr target;
210         uint8_t source_lladdr [6];
211         uint8_t todo_lancast, todo_direct;
212 };
213
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;
218
219 /* The time for the next scheduled maintenance: routersol or keepalive.
220  * The milliseconds are always 0 for maintenance tasks.
221  */
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;
228
229 /* The network packet structure of a 6bed4 Router Solicitation */
230
231 uint8_t ipv6_router_solicitation [] = {
232         // IPv6 header
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
240         0, 0, 0, 0,
241         // ICMPv6 option: source link layer address 0x0001 (end-aligned)
242         0x01, 0x01, 0, 0, 0, 0, 0x00, 0x01,
243 };
244
245 uint8_t ipv6_defaultrouter_neighbor_advertisement [] = {
246         // IPv6 header
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
254         0x40, 0, 0, 0,
255         // Target: fe80::
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
258         2, 1,
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
261 };
262
263 uint8_t router_linklocal_address [] = {
264         0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00,
265 };
266
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,
270 };
271
272 uint8_t client1_linklocal_address [] = {
273         0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01,
274 };
275
276 uint8_t allnodes_linklocal_address [] = {
277         0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01,
278 };
279
280 uint8_t allrouters_linklocal_address [] = {
281         0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x02,
282 };
283
284 uint8_t solicitednodes_linklocal_prefix [13] = {
285         0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0xff
286 };
287
288 bool default_route = false;
289
290 bool foreground = false;
291
292 bool log_to_stderr = false;
293
294 bool multicast = true;
295
296
297 /*
298  *
299  * Driver routines
300  *
301  */
302
303 #ifndef INTERFACE_NAME_6BED4
304 #define INTERFACE_NAME_6BED4 "6bed4"
305 #endif
306
307 #ifdef LINUX
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.
313  */
314 bool setup_tunnel (void) {
315         if (v6sox == -1) {
316                 v6sox = open ("/dev/net/tun", O_RDWR);
317         }
318         if (v6sox == -1) {
319                 syslog (LOG_ERR, "%s: Failed to access tunnel driver on /dev/net/tun: %s\n", program, strerror (errno));
320                 return 0;
321         }
322         bool ok = true;
323         int flags = fcntl (v6sox, F_GETFL, 0);
324         if (flags == -1) {
325                 syslog (LOG_CRIT, "Failed to retrieve flags for the tunnel file descriptor: %s\n", strerror (errno));
326                 ok = false;
327         }
328         if (!have_tunnel) {
329                 memset (&ifreq, 0, sizeof (ifreq));
330                 strncpy (ifreq.ifr_name, INTERFACE_NAME_6BED4, IFNAMSIZ);
331 #ifdef PEER_USE_TAP
332                 ifreq.ifr_flags = IFF_TAP | IFF_NO_PI;
333 #else
334                 ifreq.ifr_flags = IFF_TUN;
335 #endif
336                 if (ok && (ioctl (v6sox, TUNSETIFF, (void *) &ifreq) == -1)) {
337                         syslog (LOG_CRIT, "Failed to set interface name: %s\n", strerror (errno));
338                         ok = false;
339                 } else {
340                         have_tunnel = ok;
341                 }
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);
346         }
347         char cmd [512+1];
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);
351                 ok = false;
352         }
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);
356                 ok = false;
357         }
358         if (!ok) {
359                 close (v6sox);  /* This removes the tunnel interface */
360                 v6sox = -1;
361         }
362         return ok;
363 }
364
365 bool setup_tunnel_address (void) {
366         bool ok = have_tunnel;
367         char cmd [512+1];
368
369         snprintf (cmd, 512, "/sbin/sysctl -q -w net.ipv6.conf.%s.autoconf=0", ifreq.ifr_name);
370         if (ok && system (cmd) != 0) {
371                 ok = 0;
372         }
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);
376                 ok = false;
377         }
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);
381                 ok = false;
382         }
383         if (default_route) {
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);
387                         ok = false;
388                 }
389         }
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);
394                         ok = false;
395                 }
396         }
397         return ok;
398 }
399 #endif /* LINUX */
400
401
402
403 /*
404  *
405  * Extension Hook Functions
406  *
407  */
408
409
410 /* Extension hook to deliver a new IPv6 address range that others may use.
411  */
412 void exthook_add_range_offer (struct in6_addr *start, struct in6_addr *end) {
413         if (exthook == NULL) {
414                 return;
415         }
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);
420         char cmd [512+1];
421         snprintf (cmd, 512, "%s %d add-range-offer %s %s",
422                                 exthook, getpid (),
423                                 startstr, endstr);
424         if (system (cmd) != 0) {
425                 fprintf (stderr, "Hook failed: %s\n", cmd);
426         }
427 }
428
429
430 /* Extension hook to deliver a new IPv6 route.
431  */
432 void exthook_add_route_offer (struct in6_addr *pfaddr, uint8_t pflen,
433                                 struct in6_addr *router) {
434         if (exthook == NULL) {
435                 return;
436         }
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);
441         char cmd [512+1];
442         snprintf (cmd, 512, "%s %d add-route-offer %s %d %s",
443                                 exthook, getpid (),
444                                 pfaddrstr, pflen, routerstr);
445         if (system (cmd) != 0) {
446                 fprintf (stderr, "Hook failed: %s\n", cmd);
447         }
448 }
449
450
451 /* Extension hook to remove past offers by this process.
452  * This one is special; it is run during orderly shutdown.
453  */
454 void exthook_del_offers (void) {
455         if (exthook == NULL) {
456                 return;
457         }
458         char cmd [512+1];
459         snprintf (cmd, 512, "%s %d del-offers",
460                                 exthook, getpid ());
461         if (system (cmd) != 0) {
462                 fprintf (stderr, "Hook failed: %s\n", cmd);
463         }
464 }
465
466
467 /*
468  *
469  * Utility functions
470  *
471  */
472
473
474
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
479  */
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;
488 }
489
490
491 /* Look for an entry in the 50ms-cycled Neighbor Discovery queue.
492  * Match the target address.  Return the entry found, or NULL.
493  */
494 struct ndqueue *findqueue (struct in6_addr *target) {
495         struct ndqueue *ndq = ndqueue;
496         if (ndq) {
497                 do {
498                         if (memcmp (target, &ndq->target, 16) == 0) {
499                                 return ndq;
500                         }
501                         ndq = ndq->next;
502                 } while (ndq != ndqueue);
503         }
504         return NULL;
505 }
506
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?"
510  */
511 static int TODO_qlen;
512 void enqueue (struct in6_addr *target, struct in6_addr *v6src, uint8_t *source_lladdr) {
513         //
514         // Refuse to create double entries
515         if (findqueue (target)) {
516                 return;
517         }
518         //
519         // Allocate a free item to enqueue
520         struct ndqueue *new = freequeue;
521         if (!new) {
522                 // Temporarily overflown with ND -> drop the request
523                 return;
524         }
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;
528         //
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;
535         //
536         // Time the new item to run instantly
537         new->tv.tv_sec = 0;
538         //
539         // Enqueue the new item in front of the queue
540         if (ndqueue) {
541                 new->next = ndqueue->next;
542                 ndqueue->next = new;
543         } else {
544                 new->next = new;
545                 ndqueue = new;
546         }
547 }
548
549 /* Remove an item from the 50ms-cycled Neighbor Discovery queue.
550  * Enter its storage space in the free queue.
551  */
552 void dequeue (struct ndqueue *togo) {
553         struct ndqueue *prev = ndqueue;
554         do {
555                 if (prev->next == togo) {
556                         if (togo->next != togo) {
557                                 prev->next = togo->next;
558                                 if (ndqueue == togo) {
559                                         ndqueue = togo->next;
560                                 }
561                         } else {
562                                 // Must be the only queued item
563                                 ndqueue = NULL;
564                         }
565                         togo->next = freequeue;
566                         freequeue = togo;
567 syslog (LOG_DEBUG, "Queue-- => %d\n", --TODO_qlen);
568                         return;
569                 }
570                 prev = prev->next;
571         } while (prev != ndqueue);
572 }
573
574
575 /*
576  * Calculate the ICMPv6 checksum field
577  */
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 };
583         uint32_t csum = 0;
584         u_int8_t i, j;
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]);
589                 }
590         }
591         csum = (csum & 0xffff) + (csum >> 16);
592         csum = (csum & 0xffff) + (csum >> 16);
593         csum = htons (~csum);
594         return csum;
595 }
596
597
598 /*
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
601  * lower metric.
602  *
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
605  *       the IPv6 stack.
606  */
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;
610         v6icmp6code = 0;
611         v6icmp6data [0] =
612         v6icmp6data [1] =
613         v6icmp6data [2] =
614         v6icmp6data [3] = 0;            // Reserved
615         memcpy (v6icmp6data + 4, &v6listen, 16);
616                                         // Target IPv6 address
617         switch (ngbc_metric) {
618                                         // Destination Address suggestion
619         case METRIC_LOW:
620                 //
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;
629                 break;
630         case METRIC_MEDIUM:
631                 memcpy (v6icmp6data + 4 + 16, v6listen_linklocal_complete, 16);
632                 break;
633         case METRIC_HIGH:
634         default:
635                 return;         /* no cause for Redirect, drop */
636         }
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);
643
644
645
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.
650  */
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
657 #else
658         //TODO// Temporary fix: "ip -6 addr add .../64 dev 6bed4"
659         v6icmp6data [optidx++] = 0x80;  // L=1, A=0, Reserved1=0
660 #endif
661         memset (v6icmp6data + optidx, endlife? 0x00: 0xff, 8);
662         optidx += 8;
663                                         // Valid Lifetime: Zero / Infinite
664                                         // Preferred Lifetime: Zero / Infinite
665         memset (v6icmp6data + optidx, 0, 4);
666         optidx += 4;
667                                         // Reserved2=0
668         addr_6bed4 ((struct in6_addr *) (v6icmp6data + optidx), 0);
669                                         // Set IPv6 prefix
670         optidx += 16;
671         return optidx;
672 }
673
674
675 /*
676  * Construct a Neighbor Advertisement message, providing the
677  * Public 6bed4 Service as the link-local address.
678  *
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.
683  *
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.
687  */
688 void advertise_6bed4_public_service (struct ndqueue *info) {
689 #ifdef PEER_USE_TAP
690
691         if (info) {
692                 memcpy (v6ether.h_dest, info->source_lladdr, 6);
693         } else {
694                 memcpy (v6ether.h_dest, v6ether.h_source, 6);
695         }
696         memcpy (v6ether.h_source, SERVER_6BED4_PORT_IPV4_MACSTR, 6);
697 #endif
698         memcpy (v6data, ipv6_defaultrouter_neighbor_advertisement, 8);
699         if (info) {
700                 memcpy (v6dst6, &info->source, 16);
701         } else {
702                 memcpy (v6dst6, v6src6, 16);
703         }
704         if (info) {
705                 memcpy (v6src6, &info->target, 16);
706         } else {
707                 memcpy (v6src6, router_linklocal_address_complete, 16);
708         }
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);
711         if (info) {
712                 // Overwrite target only for queued requests
713                 memcpy (&v6icmp6data [4], &info->target, 16);
714         }
715         v6icmp6csum = icmp6_checksum ((uint8_t *) v6hdr6, 32);
716         int sent = write (v6sox, &v6data6, HDR_SIZE + sizeof (ipv6_defaultrouter_neighbor_advertisement));
717         if (info) {
718                 syslog (LOG_DEBUG, "TODO: Neighbor Discovery failed to contact directly -- standard response provided\n");
719         } else {
720                 syslog (LOG_DEBUG, "TODO: Neighbor Discovery for Public 6bed4 Service -- standard response provided\n");
721         }
722 }
723
724
725 /*
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.
729  */
730 bool validate_originator (struct in6_addr *ip6) {
731         uint32_t addr;
732         //
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)) {
737                 return true;
738         }
739         //
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) {
745                         return false;
746                 }
747         }
748         //
749         // Require the sender port to appear in its IPv6 address
750         if (v4name.sin_port != ip6->s6_addr16 [6]) {
751                 return false;
752         }
753         //
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)) {
758                 return false;
759         }
760         //
761         // We passed with flying colours
762         return true;
763 }
764
765
766 /*
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.
772  */
773 metric_t lladdr_metric (uint8_t *lladdr) {
774         uint32_t ipv4 = * (uint32_t *) (lladdr + 2);
775         //
776         // Metric 2: The 6bed4 Router address
777         if (ipv4 == v4peer.sin_addr.s_addr) {
778                 return METRIC_HIGH;
779         }
780         //
781         // Metric 0: Private Addresses, as per RFC 1918
782         if ((ipv4 & 0xff000000) == 0x0a000000) {
783                 return METRIC_LOW;      /* 10.0.0./8 */
784         }
785         if ((ipv4 & 0xffff0000) == 0xc0a80000) {
786                 return METRIC_LOW;      /* 192.168.0.0/16 */
787         }
788         if ((ipv4 & 0xfff00000) == 0xac100000) {
789                 return METRIC_LOW;      /* 172.16.0.0/12 */
790         }
791         //
792         // Metric 1: Direct IPv4 contact is any other address
793         //           Correctness should be checked elsewhere
794         return METRIC_MEDIUM;
795 }
796
797
798 /*
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.
802  *
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...
809  *
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.
818  */
819 bool lookup_neighbor (uint8_t *ipv6, uint8_t *lladdr) {
820         struct mymsg {
821                 struct nlmsghdr hd;
822                 struct ndmsg nd;
823                 uint8_t arg [16384];
824         } msg;
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?
834 #if 0
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);
840 #endif
841         if (send (rtsox, &msg, msg.hd.nlmsg_len, MSG_DONTWAIT) == -1) {
842                 return false;
843         }
844         ssize_t recvlen;
845         uint16_t pos = 0;
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);
849                 recvlen += pos;
850                 pos = 0;
851                 struct mymsg *resp;
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) {
858                                 return false;
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);
861                                 ok = false;
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);
868                                 ok = false;
869                         } else
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");
872                                 ok = false;
873                         }
874                         struct rtattr *ra = (struct rtattr *) ((char *) &resp + pos + sizeof (struct nlmsghdr) + sizeof (struct ndmsg) + 8);
875                         ssize_t rapos = 0;
876                         while (ok && (rapos + ra->rta_len <= resp->hd.nlmsg_len)) {
877                                 switch (ra->rta_type) {
878                                 case NDA_DST:
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) {
881                                                 match = true;
882                                         }
883                                         break;
884                                 case NDA_LLADDR:
885                                         result = RTA_DATA (ra);
886                                         break;
887                                 case NDA_PROBES:
888                                 case NDA_CACHEINFO:
889                                 default:
890                                         break;  /* not of interest, skip */
891                                 }
892                                 rapos += ((ra->rta_len - 1) | 0x00000003) + 1;
893                                 ra = (struct rtattr *) (((char *) ra) + (((ra->rta_len - 1) | 0x0000003) + 1));
894                         }
895                         if (ok && match && result) {
896                                 memcpy (lladdr, result, 6);
897                                 return true;    /* Yippy! Erfolg! */
898                         }
899                         pos += resp->hd.nlmsg_len;
900                 }
901                 // Copy remaining partial message to the beginning, continue from there
902                 memcpy (&msg, ((char *) &msg) + pos, recvlen - pos);
903                 pos = recvlen - pos;
904         }
905         return false;
906 }
907
908
909 /*
910  * Major packet processing functions
911  */
912
913
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?
917  */
918 void handle_4to6_plain (ssize_t v4datalen, struct sockaddr_in *sin) {
919         //
920         // Send the unwrapped IPv6 message out over v6sox
921 #ifdef PEER_USE_TAP
922         v4ether.h_proto = htons (ETH_P_IPV6);
923         memcpy (v4ether.h_dest,   v6lladdr, 6);
924         memcpy (v4ether.h_source + 0, &sin->sin_port, 2);
925         memcpy (v4ether.h_source + 2, &sin->sin_addr, 4);
926 #endif
927 syslog (LOG_INFO, "Writing IPv6, result = %zd\n",
928         write (v6sox, &v4data6, HDR_SIZE + v4datalen)
929 )
930         ;
931 }
932
933
934 /* Handle the IPv4 message pointed at by msg as a neighbouring command.
935  *
936  * Type Code    ICMPv6 meaning                  Handling
937  * ---- ----    -----------------------------   ----------------------------
938  * 133  0       Router Solicitation             Ignore
939  * 134  0       Router Advertisement            Setup Tunnel with Prefix
940  * 135  0       Neighbour Solicitation          Send Neighbour Advertisement
941  * 136  0       Neighbour Advertisement         Ignore
942  * 137  0       Redirect                        Ignore
943  */
944 void handle_4to6_nd (struct sockaddr_in *sin, ssize_t v4ngbcmdlen) {
945         uint16_t srclinklayer;
946         uint8_t *destprefix = NULL;
947 #ifdef TODO_DEPRECATED
948         uint8_t *destlladdr = NULL;
949 #endif
950         struct ndqueue *ndq;
951         if (v4ngbcmdlen < sizeof (struct ip6_hdr) + sizeof (struct icmp6_hdr)) {
952                 return;
953         }
954         //
955         if (v4v6icmpcode != 0) {
956                 return;
957         }
958         if (icmp6_checksum (v4data, v4ngbcmdlen - sizeof (struct ip6_hdr)) != v4v6icmpcksum) {
959                 return;
960         }
961         //
962         // Approved.  Perform neighbourly courtesy.
963         switch (v4v6icmptype) {
964         case ND_ROUTER_SOLICIT:
965                 return;         /* this is not a router, drop */
966         case ND_ROUTER_ADVERT:
967                 //
968                 // Validate Router Advertisement
969                 if (ntohs (v4v6plen) < sizeof (struct icmp6_hdr) + 16) {
970                         return;   /* strange length, drop */
971                 }
972                 if (v4v6icmpdata [1] & 0x80 != 0x00) {
973                         return;   /* indecent proposal to use DHCPv6, drop */
974                 }
975                 if (memcmp (&v4src6->s6_addr, router_linklocal_address, 16) != 0) {
976                         return;   /* not from router, drop */
977                 }
978                 if (memcmp (&v4dst6->s6_addr, client1_linklocal_address, 8) != 0) {
979                         if (memcmp (&v4dst6->s6_addr, allnodes_linklocal_address, 16) != 0) {
980                                 return;   /* no address setup for me, drop */
981                         }
982                 }
983                 if (v4dst6->s6_addr [8] & 0x01) {
984                         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");
985                 }
986                 //
987                 // Parse the Router Advertisement
988                 size_t rdofs = 12;
989                 int v6route_count_old = v6route_count;
990                 //TODO:+4_WRONG?// while (rdofs <= ntohs (v4v6plen) + 4) { ... }
991                 while (rdofs + 4 < ntohs (v4v6plen)) {
992                         if (v4v6icmpdata [rdofs + 1] == 0) {
993                                 return;   /* zero length option */
994                         }
995 #ifdef TODO_DEPRACATED
996                         if ((v4v6icmpdata [rdofs + 0] == ND_OPT_DESTINATION_LINKADDR) && (v4v6icmpdata [rdofs + 1] == 1)) {
997                                 if (v4v6icmpdata [rdofs + 2] & 0x01) {
998                                         syslog (LOG_WARNING, "TODO: Ignoring an odd UDP port offered in a Router Advertisement over 6bed4\n");
999                                 }
1000                                 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]);
1001                                 destlladdr = &v4v6icmpdata [rdofs + 2];
1002                                 /* continue with next option */
1003                         } else
1004 #endif
1005                         if (v4v6icmpdata [rdofs + 0] != ND_OPT_PREFIX_INFORMATION) {
1006                                 /* skip to next option */
1007                         } else if (v4v6icmpdata [rdofs + 1] != 4) {
1008                                 return;   /* bad length field */
1009                         } else if (rdofs + (v4v6icmpdata [rdofs + 1] << 3) > ntohs (v4v6plen) + 4) {
1010                                 return;   /* out of packet length */
1011                         } else if ((v4v6icmpdata [rdofs + 3] & 0xc0) != 0xc0) {
1012                                 /* no on-link autoconfig, but routable prefix */
1013                                 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]);
1014                                 if (v6route_count_old > 0) {
1015                                         v6route_count = v6route_count_old = 0;
1016                                 }
1017                                 if ((v6route_count < MAX_ROUTABLE_PREFIXES) &&
1018                                                 (v4v6icmpdata [rdofs + 2] <= 128) &&
1019                                                 (v4v6icmpdata [rdofs + 2] >= 16)) {
1020                                         memcpy (
1021                                                 v6route_addr [v6route_count].s6_addr,
1022                                                 &v4v6icmpdata [rdofs+16],
1023                                                 16);
1024                                         v6route_pfix [v6route_count] =
1025                                                 v4v6icmpdata [rdofs + 2];
1026                                         v6route_count++;
1027                                 }
1028                         } else if (v4v6icmpdata [rdofs + 2] != PREFIX_SIZE) {
1029                                 /* not a /114 prefix, so no 6bed4 offer */
1030                                 return;
1031                         } else {
1032                                 destprefix = &v4v6icmpdata [rdofs + 16];
1033                         }
1034                         rdofs += (v4v6icmpdata [rdofs + 1] << 3);
1035                 }
1036                 if (destprefix) {
1037                         if (v6route_count_old > 0) {
1038                                 v6route_count = 0;
1039                         }
1040                         memcpy (v6listen.s6_addr + 0, destprefix, 16);
1041                         v6listen.s6_addr [14] &= 0xc0;
1042                         v6listen.s6_addr [15]  = 0x01;  // choose client 1
1043                         memcpy (v6listen_linklocal_complete + 0, v6listen_linklocal, 8);
1044                         memcpy (v6listen_linklocal_complete + 8, v6listen.s6_addr + 8, 8);
1045                         memcpy (v6lladdr, destprefix + 8, 6);
1046                         //TODO// Is v6lladdr useful?  Should it include lanip?
1047                         v6lladdr [0] &= 0xfc;
1048                         v6lladdr [0] |= (destprefix [14] >> 6);
1049                         inet_ntop (AF_INET6,
1050                                 &v6listen,
1051                                 v6prefix,
1052                                 sizeof (v6prefix));
1053                         syslog (LOG_INFO, "%s: Assigning address %s to tunnel\n", program, v6prefix);
1054                         setup_tunnel_address ();  //TODO// parameters?
1055                         got_lladdr = true;
1056                         maintenance_time_cycle = maintenance_time_cycle_max;
1057                         maintenance_time_sec = time (NULL) + maintenance_time_cycle;
1058                         struct in6_addr start, end;
1059                         memcpy (&start, destprefix, 16);
1060                         memcpy (&end,   destprefix, 16);
1061                         start.s6_addr [15] |= 0x02;
1062                         end  .s6_addr [14] |= 0x3f;
1063                         end  .s6_addr [15] |= 0xff;
1064                         /* Update the extension hooks */
1065                         exthook_del_offers ();
1066                         exthook_add_range_offer (&start, &end);
1067                         for (int i = 0; i < v6route_count; i++) {
1068                                 exthook_add_route_offer (
1069                                                 &v6route_addr [i],
1070                                                 v6route_pfix [i],
1071                                                 (struct in6_addr *) destprefix);
1072                         }
1073                 }
1074                 return;
1075         case ND_NEIGHBOR_SOLICIT:
1076                 //
1077                 // Validate Neigbour Solicitation (trivial)
1078                 //
1079                 // Replicate the message over the IPv6 Link (like plain IPv6)
1080                 if (v4ngbcmdlen < 24) {
1081                         return;         /* too short, drop */
1082                 }
1083                 syslog (LOG_DEBUG, "%s: Replicating Neighbor Solicatation from 6bed4 to the IPv6 Link\n", program);
1084 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); } }
1085 uint8_t optofs = 4 + 16;
1086 #if 0
1087 uint8_t *srcll = NULL;  /* TODO -- use 6bed4 Network sender instead! */
1088 while ((40 + 4 + optofs + 2 < v4ngbcmdlen) && (40 + 4 + optofs + 8 * v4v6icmpdata [optofs + 1] <= v4ngbcmdlen)) {
1089 if (v4v6icmpdata [optofs] == 1) {
1090 srcll = v4v6icmpdata + optofs + 2;
1091 }
1092 optofs += 8 * v4v6icmpdata [optofs + 1];
1093 }
1094 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)); }
1095 #endif
1096                 //
1097                 // We should attach a Source Link-Layer Address, but
1098                 // we cannot automatically trust the one provided remotely.
1099                 // Also, we want to detect if routes differ, and handle it.
1100                 //
1101                 // 0. if no entry in the ngb.cache
1102                 //    then use 6bed4 server in ND, initiate ngb.sol to src.ll
1103                 //         impl: use 6bed4-server lladdr, set highest metric
1104                 // 1. if metric (ngb.cache) < metric (src.ll)
1105                 //    then retain ngb.cache, send Redirect to source
1106                 // 2. if metric (ngb.cache) > metric (src.ll)
1107                 //    then retain ngb.cache, initiate ngb.sol to src.ll
1108                 // 3. if metric (ngb.cache) == metric (src.ll)
1109                 //    then retain ngb.cache
1110                 //
1111                 uint8_t src_lladdr [6];
1112                 src_lladdr [0] = ntohs (v4name.sin_port) & 0x00ff;
1113                 src_lladdr [1] = ntohs (v4name.sin_port) >> 8;
1114                 memcpy (src_lladdr + 2, &v4name.sin_addr, 4);
1115                 metric_t src_metric = lladdr_metric (src_lladdr);
1116                 v4v6icmpdata [4+16+0] = 1;      /* Option: Source LLaddr */
1117                 v4v6icmpdata [4+16+1] = 1;      /* Length: 1x 8 bytes */
1118                 uint8_t *ngbc_lladdr = v4v6icmpdata + 4+16+2;
1119                 uint8_t ngbc_ipv6 [16];
1120                 if (memcmp (v4src6, v6listen_linklocal, 8)) {
1121                         memcpy (ngbc_ipv6 + 0, &v6listen, 8);
1122                         memcpy (ngbc_ipv6 + 8, v4src6 + 8, 8);
1123                 } else {
1124                         memcpy (ngbc_ipv6, v4src6, 16);
1125                 }
1126                 bool ngbc_cached = lookup_neighbor (ngbc_ipv6, ngbc_lladdr);
1127                 metric_t ngbc_metric;
1128                 if (ngbc_cached) {
1129                         ngbc_metric = lladdr_metric (ngbc_lladdr);
1130                 } else {
1131                         ngbc_metric = METRIC_HIGH; /* trigger local ngbsol */
1132                         memcpy (ngbc_lladdr, SERVER_6BED4_PORT_IPV4_MACSTR, 6);
1133 syslog (LOG_DEBUG, "Failed to find neighbor in cache, initialising it with the high metric\n");
1134                 }
1135                 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);
1136                 //
1137                 // Replicate the ngb.sol with the selected ngbc-lladdr
1138                 v4v6icmpcksum = icmp6_checksum ((uint8_t *) v4hdr6, 8 + 16 + 8);
1139                 handle_4to6_plain (40 + 24 + 8, &v4name);
1140                 //
1141                 // If needed, initiate Neigbor Solicitation to the source
1142                 // Note: Also when !ngbc_cached as the router is then cached
1143                 if (ngbc_metric > src_metric) {
1144 syslog (LOG_DEBUG, "Trying to find the more direct route that the remote peer seems to be using\n");
1145                         enqueue ((struct in6_addr *) v4src6, &v6listen, v6lladdr);
1146                 }
1147                 //
1148                 // If needed, ask the source to redo Neighbor Solicitation
1149                 if (ngbc_metric < src_metric) {
1150 syslog (LOG_DEBUG, "Redirecting the remote peer to the more efficient route that I am using\n");
1151                         redirect_reply (ngbc_lladdr, ngbc_metric);
1152                 }
1153                 return;
1154         case ND_NEIGHBOR_ADVERT:
1155                 //
1156                 // Process Neighbor Advertisement coming in over 6bed4
1157                 // First, make sure it is against an item in the ndqueue
1158                 ndq = findqueue ((struct in6_addr *) v4v6ndtarget);
1159                 if (!ndq) {
1160                         // Ignore advertisement -- it may be an attack
1161                         return;
1162                 }
1163                 // Remove the matching item from the ndqueue
1164                 dequeue (ndq);
1165                 // Replicate the Neigbor Advertisement over the IPv6 Link (like plain IPv6)
1166                 v4v6icmpdata [0] |= 0xe0;       /* Router, Solicited, Override */
1167                 v4v6icmpdata [20] = 2;          /* Target Link-Layer Address */
1168                 v4v6icmpdata [21] = 1;          /* Length: 1x 8 bytes */
1169                 v4v6icmpdata [22] = ntohs (v4name.sin_port) & 0xff;
1170                 v4v6icmpdata [23] = ntohs (v4name.sin_port) >> 8;
1171                 memcpy (v4v6icmpdata + 24, &v4name.sin_addr, 4);
1172                 v4v6plen = htons (24 + 8);
1173                 v4v6icmpcksum = icmp6_checksum ((uint8_t *) v4hdr6, 24 + 8);
1174                 handle_4to6_plain (sizeof (struct ip6_hdr) + 24 + 8, &v4name);
1175                 return;
1176         case ND_REDIRECT:
1177                 //
1178                 // Redirect indicates that a more efficient bypass exists than
1179                 // the currently used route.  The remote peer has established
1180                 // this and wants to share that information to retain a
1181                 // symmetric communication, which is helpful in keeping holes
1182                 // in NAT and firewalls open.
1183                 //
1184                 //TODO// BE EXTREMELY SELECTIVE BEFORE ACCEPTING REDIRECT!!!
1185                 //TODO:NOTYET// enqueue ((struct in6_addr *) v4v6ndtarget, &v6listen, v6lladdr);
1186                 return;
1187         }
1188 }
1189
1190
1191 /* Receive a tunnel package, and route it to either the handler for the
1192  * tunnel protocol, or to the handler that checks and then unpacks the
1193  * contained IPv6.
1194  */
1195 void handle_4to6 (int v4in) {
1196         uint8_t buf [1501];
1197         ssize_t buflen;
1198         socklen_t adrlen = sizeof (v4name);
1199         //
1200         // Receive IPv4 package, which may be tunneled or a tunnel request
1201         buflen = recvfrom (v4in,
1202                         v4data, MTU,
1203                         MSG_DONTWAIT,
1204                         (struct sockaddr *) &v4name, &adrlen
1205                 );
1206         if (buflen == -1) {
1207                 syslog (LOG_INFO, "%s: WARNING: Error receiving IPv4-side package: %s\n",
1208                                 program, strerror (errno));
1209                 return;         /* receiving error, drop */
1210         }
1211         if (buflen <= sizeof (struct ip6_hdr)) {
1212                 return;         /* received too little data, drop */
1213         }
1214         if ((v4data [0] & 0xf0) != 0x60) {
1215                 return;         /* not an IPv6 packet, drop */
1216         }
1217         if (!validate_originator (v4src6)) {
1218                 return;         /* source appears fake, drop */
1219         }
1220         /*
1221          * Distinguish types of traffic:
1222          * Non-plain, Plain Unicast, Plain Multicast
1223          */
1224         if ((v4v6nexthdr == IPPROTO_ICMPV6) &&
1225                         (v4v6icmptype >= 133) && (v4v6icmptype <= 137)) {
1226                 //
1227                 // Not Plain: Router Adv/Sol, Neighbor Adv/Sol, Redirect
1228                 if (v4v6hoplimit != 255) {
1229                         return;
1230                 }
1231                 handle_4to6_nd (&v4name, buflen);
1232         } else {
1233                 //
1234                 // Plain Unicast or Plain Multicast (both may enter)
1235                 if (v4v6hoplimit-- <= 1) {
1236                         return;
1237                 }
1238                 handle_4to6_plain (buflen, &v4name);
1239         }
1240 }
1241
1242
1243 /*
1244  * Relay an IPv6 package to 6bed4, using the link-local address as it
1245  * is found in the Ethernet header.  Trust the local IPv6 stack to have
1246  * properly obtained this destination address through Neighbor Discovery
1247  * over 6bed4.
1248  */
1249 void handle_6to4_plain_unicast (const ssize_t pktlen, const uint8_t *lladdr) {
1250         struct sockaddr_in v4dest;
1251         memset (&v4dest, 0, sizeof (v4dest));
1252         v4dest.sin_family = AF_INET;
1253         v4dest.sin_port = htons (lladdr [0] | (lladdr [1] << 8));
1254         memcpy (&v4dest.sin_addr, lladdr + 2, 4);
1255         if (v6tc != (v6hdr6->ip6_vfc & htonl (0x0ff00000))) {
1256                 v6tc = v6hdr6->ip6_vfc & htonl (0x0ff00000);
1257                 v4qos = (ntohl (v6hdr6->ip6_vfc) & 0x0ff00000) >> 24;
1258                 if (setsockopt (v4sox, IPPROTO_IP, IP_TOS, &v4qos, sizeof (v4qos)) == -1) {
1259                         syslog (LOG_ERR, "Failed to switch IPv4 socket to QoS setting 0x%02x\n", v4qos);
1260                 }
1261         }
1262         syslog (LOG_DEBUG, "%s: Sending IPv6-UDP-IPv4 to %d.%d.%d.%d:%d, result = %zd\n", program,
1263         ((uint8_t *) &v4dest.sin_addr.s_addr) [0],
1264         ((uint8_t *) &v4dest.sin_addr.s_addr) [1],
1265         ((uint8_t *) &v4dest.sin_addr.s_addr) [2],
1266         ((uint8_t *) &v4dest.sin_addr.s_addr) [3],
1267         ntohs (v4dest.sin_port),
1268                 sendto (v4sox,
1269                                 v6data,
1270                                 pktlen - HDR_SIZE,
1271                                 MSG_DONTWAIT,
1272                                 (struct sockaddr *) &v4dest,
1273                                 sizeof (struct sockaddr_in))
1274         )
1275                                 ;
1276 }
1277
1278
1279 /*
1280  * Handle a request for Neighbor Discovery over the 6bed4 Link.
1281  */
1282 void handle_6to4_nd (ssize_t pktlen) {
1283         uint8_t lldest [6];
1284         //
1285         // Validate ICMPv6 message -- trivial, trust local generation
1286         //
1287         // Handle the message dependent on its type
1288         switch (v6icmp6type) {
1289         case ND_ROUTER_SOLICIT:
1290                 v6icmp6type = ND_ROUTER_ADVERT;
1291                 v6icmp6code = 0;
1292                 v6icmp6data [0] = 0;            // Cur Hop Limit: unspec
1293                 v6icmp6data [1] = 0x18;         // M=0, O=0,
1294                                                 // H=0, Prf=11=Low
1295                                                 // Reserved=0
1296                 //TODO: wire says 0x44 for router_adv.flags
1297                 size_t writepos = 2;
1298                 memset (v6icmp6data + writepos,
1299                                 default_route? 0xff: 0x00,
1300                                 2);             // Router Lifetime
1301                 writepos += 2;
1302                 memcpy (v6icmp6data + writepos,
1303                                 "\x00\x00\x80\x00",
1304                                 4);             // Reachable Time: 32s
1305                 writepos += 4;
1306                 memcpy (v6icmp6data + writepos,
1307                                 "\x00\x00\x01\x00",
1308                                 4);             // Retrans Timer: .25s
1309                 writepos += 4;
1310                 writepos = icmp6_prefix (writepos, 0);
1311                 v6plen = htons (4 + writepos);
1312                 memcpy (v6dst6, v6src6, 16);
1313                 memcpy (v6src6, v6listen_linklocal_complete, 16);
1314                 v6icmp6csum = icmp6_checksum ((uint8_t *) v6hdr6, 4 + writepos);
1315 #ifdef PEER_USE_TAP
1316                 v6ether.h_proto = htons (ETH_P_IPV6);
1317                 memcpy (v6ether.h_dest, v6ether.h_source, 6);
1318                 memcpy (v6ether.h_source, v6lladdr, 6);
1319 #endif
1320                 syslog (LOG_INFO, "Replying Router Advertisement to the IPv6 Link, result = %zd\n",
1321                         write (v6sox, &v6data6, HDR_SIZE + sizeof (struct ip6_hdr) + 4 + writepos)
1322                 )
1323                         ;
1324                 break;
1325         case ND_ROUTER_ADVERT:
1326                 return;         /* the IPv6 Link is no router, drop */
1327         case ND_NEIGHBOR_SOLICIT:
1328                 //
1329                 // Neighbor Solicitation is treated depending on its kind:
1330                 //  - the 6bed4 Router address is answered immediately
1331                 //  - discovery for the local IPv6 address is dropped
1332                 //  - discovery for fe80::/64 addresses is answered
1333                 //  - other peers start a process in the ndqueue
1334                 if ((memcmp (v6ndtarget, router_linklocal_address, 16) == 0) ||
1335                     (memcmp (v6ndtarget, router_linklocal_address_complete, 16) == 0)) {
1336                         advertise_6bed4_public_service (NULL);
1337                 } else if (memcmp (v6ndtarget, &v6listen, 16) == 0) {
1338                         return;         /* yes you are unique, drop */
1339                 } else if (memcmp (v6ndtarget, v6listen_linklocal, 8) == 0) {
1340                         //
1341                         // Construct response for fe80::/64
1342                         v6icmp6type = ND_NEIGHBOR_ADVERT;
1343                         v6icmp6data [0] = 0x60; /* Solicited, Override */
1344                         v6icmp6data [20] = 2;   /* Target Link-Layer Address */
1345                         v6icmp6data [21] = 1;   /* Length is 1x 8 bytes */
1346                         v6icmp6data [22] = v6icmp6data [12] ^ 0x02;
1347                         v6icmp6data [23] = v6icmp6data [13];
1348                         v6icmp6data [24] = v6icmp6data [14];
1349                         v6icmp6data [25] = v6icmp6data [17];
1350                         v6icmp6data [26] = v6icmp6data [18];
1351                         v6icmp6data [27] = v6icmp6data [19];
1352                         v6plen = htons (4 + 28);
1353                         memcpy (v6dst6, v6src6, 16);
1354                         memcpy (v6src6, &v6listen, 16);
1355 #ifdef PEER_USE_TAP
1356                         memcpy (v6ether.h_dest, v6ether.h_source, 6);
1357                         memcpy (v6ether.h_source, v6lladdr, 6);
1358 #endif
1359                         v6icmp6csum = icmp6_checksum ((uint8_t *) v6hdr6, 4 + 28);
1360 syslog (LOG_DEBUG, "Sending trivial reply to fe80::/64 type query\n");
1361                         write (v6sox, &v6data6, HDR_SIZE + sizeof (struct ip6_hdr) + 4 + 28);
1362                         return;
1363                 } else {
1364 // TODO
1365 #ifdef PEER_USE_TAP
1366                         enqueue ((struct in6_addr *) v6ndtarget, (struct in6_addr *) v6src6, v6ether.h_source);
1367 #endif
1368                 }
1369                 break;
1370         case ND_NEIGHBOR_ADVERT:
1371                 lldest [0] = v6dst6->s6_addr [8] ^ 0x02;
1372                 lldest [1] = v6dst6->s6_addr [9];
1373                 lldest [2] = v6dst6->s6_addr [10];
1374                 lldest [3] = v6dst6->s6_addr [13];
1375                 lldest [4] = v6dst6->s6_addr [14];
1376                 lldest [5] = v6dst6->s6_addr [15];
1377                 handle_6to4_plain_unicast (pktlen, lldest);
1378                 break;
1379         case ND_REDIRECT:
1380                 //TODO:NOT_IMPLEMENTED_YET:ND_REDIRECT_FROM_6BED4//
1381                 //
1382                 // Redirect indicates that a more efficient bypass exists than
1383                 // the currently used route.  The remote peer has established
1384                 // this and wants to share that information to retain a
1385                 // symmetric communication, which is helpful in keeping holes
1386                 // in NAT and firewalls open.
1387                 //
1388                 return;
1389         }
1390 }
1391
1392 /*
1393  * Receive an IPv6 package, check its address and pickup IPv4 address and
1394  * port, then package it as a tunnel message and forward it to IPv4:port.
1395  * Rely on the proper formatting of the incoming IPv6 packet, as it is
1396  * locally generated.
1397  */
1398 void handle_6to4 (void) {
1399 #ifndef PEER_USE_TAP
1400         static uint8_t lladdr [] =
1401         {
1402                 // UDP port
1403                 UDP_PORT_6BED4 & 0xff,
1404                 UDP_PORT_6BED4 >> 8,
1405                 // IPv4 address
1406                 SERVER_6BED4_IPV4_INT0,
1407                 SERVER_6BED4_IPV4_INT1,
1408                 SERVER_6BED4_IPV4_INT2,
1409                 SERVER_6BED4_IPV4_INT3
1410         };
1411 #endif
1412         //
1413         // Receive the IPv6 package and ensure a consistent size
1414         size_t rawlen = read (v6sox, &v6data6, sizeof (v6data6));
1415         if (rawlen == -1) {
1416                 return;         /* failure to read, drop */
1417         }
1418         if (rawlen < HDR_SIZE + sizeof (struct ip6_hdr) + 1) {
1419                 return;         /* packet too small, drop */
1420         }
1421 #ifdef PEER_USE_TAP
1422         if (v6ether.h_proto != htons (ETH_P_IPV6)) {
1423                 return;         /* not IPv6, drop */
1424         }
1425 //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]);
1426         //
1427         // Ignore messages from the IPv6 stack to itself
1428         if (memcmp (v6ether.h_dest, v6ether.h_source, 6) == 0) {
1429                 syslog (LOG_DEBUG, "TODO: Self-to-self messaging in IPv6 stack ignored\n");
1430                 return;
1431         }
1432 #endif
1433         /*
1434          * Distinguish types of traffic:
1435          * Non-plain, Plain Unicast, Plain Multicast
1436          */
1437         if ((v6type == IPPROTO_ICMPV6) &&
1438                         (v6icmp6type >= 133) && (v6icmp6type <= 137)) {
1439                 //
1440                 // Not Plain: Router Adv/Sol, Neighbor Adv/Sol, Redirect
1441 syslog (LOG_DEBUG, "Forwarding non-plain unicast from IPv6 to 6bed4\n");
1442                 handle_6to4_nd (rawlen);
1443         } else if ((v6dst6->s6_addr [0] != 0xff) && !(v6dst6->s6_addr [8] & 0x01)) {
1444                 //
1445                 // Plain Unicast
1446                 if (v6hops-- <= 1) {
1447                         return;
1448                 }
1449 syslog (LOG_DEBUG, "Forwarding plain unicast from IPv6 to 6bed4\n");
1450 #ifdef PEER_USE_TAP
1451                 handle_6to4_plain_unicast (rawlen, v6ether.h_dest);
1452 #else
1453                 handle_6to4_plain_unicast (rawlen, lladdr);
1454 #endif
1455
1456         } else {
1457                 //
1458                 // Plain Multicast
1459                 //TODO:IGNORE_MULTICAST//
1460                 //TODO// syslog (LOG_DEBUG, "%s: Plain multicast from 6bed4 Link to 6bed4 Network is not supported\n", program);
1461         }
1462 }
1463
1464
1465 /*
1466  * Send a single Neighbor Solicitation message over 6bed4.  This will
1467  * be sent to the given 6bed4 address, and is usually part of a series
1468  * of attempts to find a short-cut route to the 6bed4 peer.
1469  */
1470 void solicit_6bed4_neighbor (const struct ndqueue *info, const uint8_t *addr6bed4) {
1471         memcpy (v6src6, &info->source, 16);
1472         memcpy (v6dst6, &info->target, 16);
1473         v6type = IPPROTO_ICMPV6;
1474         v6hops = 255;
1475         v6icmp6type = ND_NEIGHBOR_SOLICIT;
1476         v6icmp6code = 0;
1477         v6icmp6data [0] =
1478         v6icmp6data [1] =
1479         v6icmp6data [2] =
1480         v6icmp6data [3] = 0x00;
1481         memcpy (v6icmp6data + 4, &info->target, 16);
1482         v6icmp6data [20] = 1;   // option type is Source Link-Layer Address
1483         v6icmp6data [21] = 1;   // option length is 1x 8 bytes
1484         memcpy (v6icmp6data + 22, v6lladdr, 6);
1485         uint16_t pktlen = sizeof (struct ip6_hdr) + 4 + 28;
1486         //OLD// v6icmp6csum = icmp6_checksum ((uint8_t *) v6hdr6, 28 + 8);
1487         v6plen = htons (4 + 28);
1488         v6icmp6csum = icmp6_checksum ((uint8_t *) v6hdr6, 4 + 28);
1489         handle_6to4_plain_unicast (sizeof (struct ip6_hdr) + 8 + 28 + 10, addr6bed4);
1490         //TODO// Why these +8 and +10 are needed, I don't know yet!
1491 }
1492
1493
1494 /*
1495  * Find a neighbor's 6bed4 address.  This is coordinated by the ndqueue,
1496  * which schedules such tasks and makes them repeat.  Furthermore, a few
1497  * attempts may be scheduled on the local network before attempts
1498  * shift to the direct target IPv4/UDP addresses.  Of course the local
1499  * network will only be scheduled if the public IPv4 address matches
1500  * the one for the local node.
1501  *
1502  * This process is dequeued by reverse Neighbor Advertisements.  If none
1503  * comes back in spite of the various Neighbor Solicitations sent, then
1504  * the final action is to send a Neighbor Advertisement to the host with
1505  * the Public 6bed4 Service as its target of last resort.  In case of
1506  * this last resort, the process is not continued any further; the
1507  * return value indicates whether the queue entry should be kept for
1508  * another round.
1509  */
1510 bool chase_neighbor_6bed4_address (struct ndqueue *info) {
1511         uint8_t addr6bed4 [6];
1512         static const uint8_t addr6bed4_lancast [8] = {
1513                 UDP_PORT_6BED4 & 0xff, UDP_PORT_6BED4 >> 8,
1514                 224, 0, 0, 1
1515         };
1516         if (info->todo_lancast > 0) {
1517                 // Attempt 1. Send to LAN multicast address (same public IP)
1518                 info->todo_lancast--;
1519                 solicit_6bed4_neighbor (info, addr6bed4_lancast);
1520                 return true;
1521         } else if (info->todo_direct > 0) {
1522                 // Attempt 2. Send to target's direct IP address / UDP port
1523                 info->todo_direct--;
1524                 addr6bed4 [0] = info->target.s6_addr [8] ^ 0x02;
1525                 addr6bed4 [1] = info->target.s6_addr [9];
1526                 addr6bed4 [2] = info->target.s6_addr [10];
1527                 addr6bed4 [3] = info->target.s6_addr [13];
1528                 addr6bed4 [4] = info->target.s6_addr [14];
1529                 addr6bed4 [5] = info->target.s6_addr [15];
1530                 solicit_6bed4_neighbor (info, addr6bed4);
1531                 return true;
1532         } else {
1533                 // Attempt 3. Respond with Public 6bed4 Service
1534                 syslog (LOG_INFO, "%s: Failed to find a bypass, passing back the 6bed4 Router\n", program);
1535                 advertise_6bed4_public_service (info);
1536                 return false;
1537         }
1538 }
1539
1540
1541 /*
1542  * Perform Router Solicitation.  This is the usual mechanism that is used
1543  * on ethernet links as well, except that the 6bed4 permits fixed interface
1544  * identifiers; for this client, the interface identifier will be 0x0001.
1545  * The router always has interface identifier 0x0000 but it will now be
1546  * addressed at the all-routers IPv6 address 0xff02::2 with the general
1547  * source IPv6 address ::
1548  */
1549 void solicit_router (void) {
1550         v4name.sin_family = AF_INET;
1551         memcpy (&v4name.sin_addr.s_addr, &v4listen, 4);
1552         v4name.sin_port = htons (UDP_PORT_6BED4);
1553         int done = 0;
1554         int secs = 1;
1555 // syslog (LOG_DEBUG, "%s: Sending RouterSolicitation-IPv6-UDP-IPv4 to %d.%d.%d.%d:%d, result = %d\n", program,
1556 // ((uint8_t *) &v4name.sin_addr.s_addr) [0],
1557 // ((uint8_t *) &v4name.sin_addr.s_addr) [1],
1558 // ((uint8_t *) &v4name.sin_addr.s_addr) [2],
1559 // ((uint8_t *) &v4name.sin_addr.s_addr) [3],
1560 // ntohs (v4name.sin_port),
1561 (
1562         sendto (v4sox,
1563                         ipv6_router_solicitation,
1564                         sizeof (ipv6_router_solicitation),
1565                         MSG_DONTWAIT,
1566                         (struct sockaddr *) &v4name, sizeof (v4name)));
1567 }
1568
1569
1570 /*
1571  * Send a KeepAlive message.  This is an UDP/IPv4 message with no contents.
1572  * The router will not respond, but that is okay; outgoing traffic is the
1573  * way to keep holes in NAT and firewalls open.
1574  */
1575 void keepalive (void) {
1576         v4name.sin_family = AF_INET;
1577         memcpy (&v4name.sin_addr.s_addr, &v4listen, 4);
1578         v4name.sin_port = htons (UDP_PORT_6BED4);
1579         int done = 0;
1580         int secs = 1;
1581         setsockopt (v4sox, IPPROTO_IP, IP_TTL, &keepalive_ttl, sizeof (keepalive_ttl));
1582         sendto (v4sox,
1583                         "",
1584                         0,
1585                         MSG_DONTWAIT,
1586                         (struct sockaddr *) &v4name, sizeof (v4name));
1587         setsockopt (v4sox, IPPROTO_IP, IP_TTL, &v4ttl, sizeof (v4ttl));
1588 }
1589
1590
1591 /* Regular maintenance is a routine that runs regularly to do one of two
1592  * generic tasks: either it sends Router Solicitation messages to the
1593  * Public 6bed4 Service, or it sends an empty UDP message somewhat in its
1594  * direction to keep NAT/firewall holes open.
1595  */
1596 void regular_maintenance (void) {
1597         if (!got_lladdr) {
1598                 solicit_router ();
1599                 maintenance_time_cycle <<= 1;
1600                 maintenance_time_cycle += 1;
1601                 if (maintenance_time_cycle > maintenance_time_cycle_max) {
1602                         maintenance_time_cycle = maintenance_time_cycle_max;
1603                 }
1604                 syslog (LOG_INFO, "Sent Router Advertisement to Public 6bed4 Service, next attempt in %ld seconds\n", maintenance_time_cycle);
1605         } else {
1606                 syslog (LOG_INFO, "Sending a KeepAlive message (empty UDP) to the 6bed4 Router\n");
1607                 keepalive ();
1608                 maintenance_time_cycle = maintenance_time_cycle_max;
1609         }
1610         maintenance_time_sec = time (NULL) + maintenance_time_cycle;
1611 }
1612
1613
1614 /* Indicate that the running daemon should stop.  This is intended as a
1615  * signal handler function, and would instruct the select() loop to
1616  * terminate.
1617  */
1618 void signal_daemon (int signum) {
1619         signalnum = signum;
1620 }
1621
1622
1623 /* Run the daemon core code, passing information between IPv4 and IPv6 and
1624  * responding to tunnel requests if so requested.  The loop ends when a
1625  * suitable signal is received: HUP, INT, KILL, TERM.
1626  */
1627 void run_daemon (void) {
1628         atexit (exthook_del_offers);
1629         fd_set io;
1630         bool keep;
1631         maintenance_time_sec = 0;       // trigger Router Solicitation
1632         signal (SIGHUP,  signal_daemon);
1633         signal (SIGINT,  signal_daemon);
1634         signal (SIGKILL, signal_daemon);
1635         signal (SIGTERM, signal_daemon);
1636         FD_ZERO (&io);
1637         FD_SET (v4sox, &io);
1638         FD_SET (v6sox, &io);
1639         int nfds = (v4sox < v6sox)? (v6sox + 1): (v4sox + 1);
1640         if (v4mcast != -1) {
1641                 FD_SET (v4mcast, &io);
1642                 if (v4mcast >= nfds) {
1643                         nfds = v4mcast + 1;
1644                 }
1645         }
1646         while (signalnum == 0) {
1647                 struct timeval tout;
1648                 struct timeval now;
1649                 gettimeofday (&now, NULL);
1650                 if (maintenance_time_sec <= now.tv_sec) {
1651                         regular_maintenance ();
1652                 }
1653                 tout.tv_sec = maintenance_time_sec - now.tv_sec;
1654                 tout.tv_usec = 0;
1655                 while (ndqueue && (
1656                                 ((ndqueue->next->tv.tv_sec == now.tv_sec)
1657                                   && (ndqueue->next->tv.tv_usec <= now.tv_usec))
1658                                 || (ndqueue->next->tv.tv_sec < now.tv_sec))) {
1659                         //
1660                         // Run the entry's handler code
1661                         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);
1662                         keep = chase_neighbor_6bed4_address (ndqueue->next);
1663                         if (!keep) {
1664                                 dequeue (ndqueue->next);
1665                                 continue;
1666                         }
1667                         //
1668                         // Make ndqueue point to the entry to run
1669                         ndqueue = ndqueue->next;
1670                         //
1671                         // Add 50ms to the running time
1672                         if (now.tv_usec < 950000) {
1673                                 ndqueue->tv.tv_usec = now.tv_usec +   50000;
1674                                 ndqueue->tv.tv_sec  = now.tv_sec  + 0;
1675                         } else {
1676                                 ndqueue->tv.tv_usec = now.tv_usec -  950000;
1677                                 ndqueue->tv.tv_sec  = now.tv_sec  + 1;
1678                         }
1679                 }
1680                 if (ndqueue && ((ndqueue->next->tv.tv_sec - now.tv_sec) < tout.tv_sec)) {
1681                         tout.tv_sec  = ndqueue->next->tv.tv_sec  - now.tv_sec ;
1682                         tout.tv_usec = ndqueue->next->tv.tv_usec - now.tv_usec;
1683                         if (tout.tv_usec < 0) {
1684                                 tout.tv_usec += 1000000;
1685                                 tout.tv_sec  -= 1;
1686                         }
1687                 }
1688                 if (select (nfds, &io, NULL, NULL, &tout) < 0) {
1689                         if (errno == EINTR) {
1690                                 return;
1691                         }
1692                         syslog (LOG_ERR, "Select failed: %s\n", strerror (errno));
1693                 }
1694                 if (FD_ISSET (v4sox, &io)) {
1695 syslog (LOG_DEBUG, "Got unicast input\n");
1696                         handle_4to6 (v4sox);
1697                 } else {
1698                         FD_SET (v4sox, &io);
1699                 }
1700                 if (FD_ISSET (v6sox, &io)) {
1701                         handle_6to4 ();
1702                 } else {
1703                         FD_SET (v6sox, &io);
1704                 }
1705                 if (v4mcast != -1) {
1706                         if (FD_ISSET (v4mcast, &io)) {
1707 syslog (LOG_DEBUG, "WOW: Got multicast input\n");
1708                                 handle_4to6 (v4mcast);
1709                         } else {
1710                                 FD_SET (v4mcast, &io);
1711                         }
1712                 }
1713 //fflush (stdout);
1714         }
1715 }
1716
1717
1718 /* Option descriptive data structures */
1719
1720 char *short_opt = "s:t:d:l:p:rk:fex:h";
1721
1722 struct option long_opt [] = {
1723         { "v4server", 1, NULL, 's' },
1724         { "tundev", 1, NULL, 'd' },
1725         { "default-route", 0, NULL, 'r' },
1726         { "listen", 1, NULL, 'l' },
1727         { "port", 1, NULL, 'p' },
1728         { "ttl", 1, NULL, 't' },
1729         { "foreground", 0, NULL, 'f' },
1730         { "fork-not", 0, NULL, 'f' },
1731         { "keepalive", 1, NULL, 'k' },
1732         { "keepalive-period-ttl", 1, NULL, 'k' },
1733         { "error-console", 0, NULL, 'e' },
1734         { "extension-hook", 1, NULL, 'x' },
1735         { "help", 0, NULL, 'h' },
1736         { NULL, 0, NULL, 0 }    /* Array termination */
1737 };
1738
1739
1740 /* Parse commandline arguments (and start to process them).
1741  * Return 1 on success, 0 on failure.
1742  */
1743 int process_args (int argc, char *argv []) {
1744         int ok = 1;
1745         int help = 0;
1746         int done = 0;
1747         unsigned long tmpport;
1748         char *endarg;
1749         default_route = false;
1750         while (!done) {
1751                 switch (getopt_long (argc, argv, short_opt, long_opt, NULL)) {
1752                 case -1:
1753                         done = 1;
1754                         if (optind != argc) {
1755                                 fprintf (stderr, "%s: Extra arguments not permitted: %s...\n", program, argv [optind]);
1756                                 ok = 0;
1757                         }
1758                         break;
1759                 case 's':
1760                         if (v4sox != -1) {
1761                                 ok = 0;
1762                                 fprintf (stderr, "%s: You can only specify a single server address\n", program);
1763                                 continue;
1764                         }
1765                         v4server = optarg;
1766                         if (inet_pton (AF_INET, optarg, &v4peer.sin_addr) <= 0) {
1767                                 ok = 0;
1768                                 fprintf (stderr, "%s: Failed to parse IPv4 address %s\n", program, optarg);
1769                                 break;
1770                         }
1771                         memcpy (&v4listen, &v4peer.sin_addr, 4);
1772                         v4sox = socket (AF_INET, SOCK_DGRAM, 0);
1773                         if (v4sox == -1) {
1774                                 ok = 0;
1775                                 fprintf (stderr, "%s: Failed to allocate UDPv4 socket: %s\n", program, strerror (errno));
1776                                 break;
1777                         }
1778                         break;
1779                 case 'd':
1780                         if (v6sox != -1) {
1781                                 ok = 0;
1782                                 fprintf (stderr, "%s: Multiple -d arguments are not permitted\n", program);
1783                                 break;
1784                         }
1785                         v6sox = open (optarg, O_RDWR);
1786                         if (v6sox == -1) {
1787                                 ok = 0;
1788                                 fprintf (stderr, "%s: Failed to open tunnel device %s: %s\n", program, optarg, strerror (errno));
1789                                 break;
1790                         }
1791                         break;
1792                 case 'r':
1793                         if (default_route) {
1794                                 fprintf (stderr, "%s: You can only request default route setup once\n", program);
1795                                 ok = 0;
1796                                 break;
1797                         }
1798                         default_route = true;
1799                         break;
1800                 case 'l':
1801                         if (inet_pton (AF_INET, optarg, &v4bind.sin_addr.s_addr) != 1) {
1802                                 fprintf (stderr, "%s: IPv4 address %s is not valid\n", program, optarg);
1803                                 ok = 0;
1804                                 break;
1805                         }
1806                         break;
1807                 case 'p':
1808                         tmpport = strtoul (optarg, &endarg, 10);
1809                         if ((*endarg) || (tmpport > 65535)) {
1810                                 fprintf (stderr, "%s: UDP port number %s is not valid\n", program, optarg);
1811                                 ok = 0;
1812                                 break;
1813                         }
1814                         if (tmpport & 0x0001) {
1815                                 fprintf (stderr, "%s: UDP port number %ld is odd, which is not permitted\n", program, tmpport);
1816                                 ok = 0;
1817                                 break;
1818                         }
1819                         v4bind.sin_port = htons (tmpport);
1820                         break;
1821                 case 'f':
1822                         if (foreground) {
1823                                 fprintf (stderr, "%s: You can only request foreground operation once\n", program);
1824                                 ok = 0;
1825                                 break;
1826                         }
1827                         foreground = true;
1828                         break;
1829                 case 'e':
1830                         if (log_to_stderr) {
1831                                 fprintf (stderr, "%s: You can only specify logging to stderr once\n", program);
1832                                 ok = 0;
1833                                 break;
1834                         }
1835                         log_to_stderr = true;
1836                         break;
1837                 case 't':
1838                         if (v4ttl_mcast != -1) {
1839                                 fprintf (stderr, "%s: You can set the ttl for multicast once\n", program);
1840                                 ok = 0;
1841                                 break;
1842                         }
1843                         char *zero;
1844                         long setting = strtol(optarg, &zero, 10);
1845                         if (*zero || (setting < 0) || (setting > 255)) {
1846                                 fprintf (stderr, "%s: Multicast radius must be a number in the range 0 to 255, inclusive, not %s\n", program, optarg);
1847                                 ok = 0;
1848                                 break;
1849                         }
1850                         v4ttl_mcast = setting;
1851                         break;
1852                 case 'k':
1853                         if (keepalive_ttl != -1) {
1854                                 fprintf (stderr, "%s: You can only set the keepalive period and TTL once\n", program);
1855                                 ok = 0;
1856                                 break;
1857                         }
1858                         char *rest;
1859                         keepalive_period = strtol (optarg, &rest, 10);
1860                         if (*rest == ',') {
1861                                 rest++;
1862                                 keepalive_ttl = strtol (rest, &rest, 10);
1863                                 if ((keepalive_ttl < 0) || (keepalive_ttl > 255)) {
1864                                         fprintf (stderr, "%s: The keepalive TTL must be in the range 0 to 255, inclusive\n", program);
1865                                         ok = 0;
1866                                         break;
1867                                 }
1868                         } else {
1869                                 keepalive_ttl = 3;
1870                         }
1871                         if (*rest) {
1872                                 fprintf (stderr, "%s: The format for keepalive configuration is 'period,ttl' or just 'period', but not %s\n", program, optarg);
1873                                 exit (1);
1874                         }
1875                         break;
1876                 case 'x':
1877                         if (exthook != NULL) {
1878                                 fprintf (stderr, "%s: You can only specify one extension hook\n", program);
1879                                 ok = 0;
1880                                 break;
1881                         }
1882                         exthook = optarg;
1883                         break;
1884                 default:
1885                         ok = 0;
1886                         /* continue into 'h' to produce usage information */
1887                 case 'h':
1888                         help = 1;
1889                         break;
1890                 }
1891                 if (help || !ok) {
1892                         done = 1;
1893                 }
1894         }
1895         if (help) {
1896 #ifdef HAVE_SETUP_TUNNEL
1897                 fprintf (stderr, "Usage: %s [-r] [-d /dev/tunX]\n       %s -h\n", program, program);
1898 #else
1899                 fprintf (stderr, "Usage: %s [-r] -d /dev/tunX\n       %s -h\n", program, program);
1900 #endif
1901                 return 0;
1902         }
1903         if (!ok) {
1904                 return 0;
1905         }
1906         if (keepalive_ttl != -1) {
1907                 maintenance_time_cycle_max = keepalive_period;
1908         } else {
1909                 keepalive_ttl = 3;
1910         }
1911 #ifdef HAVE_SETUP_TUNNEL
1912         if (v6sox == -1) {
1913                 if (geteuid () != 0) {
1914                         fprintf (stderr, "%s: You should be root, or use -d to specify an accessible tunnel device\n", program);
1915                         return 0;
1916                 } else {
1917                         ok = setup_tunnel ();
1918                         if (!ok) {
1919                                 fprintf (stderr, "Failed to setup tunnel\n");
1920                         }
1921                 }
1922         }
1923 #else /* ! HAVE_SETUP_TUNNEL */
1924         if (v6sox == -1) {
1925                 fprintf (stderr, "%s: You must specify a tunnel device with -d that is accessible to you\n", program);
1926                 return 0;
1927         }
1928 #endif /* HAVE_SETUP_TUNNEL */
1929         return ok;
1930 }
1931
1932
1933 /* The main program parses commandline arguments and forks off the daemon
1934  */
1935 int main (int argc, char *argv []) {
1936         //
1937         // Initialise
1938         program = strrchr (argv [0], '/');
1939         if (program) {
1940                 program++;
1941         } else {
1942                 program = argv [0];
1943         }
1944         memset (&v4name, 0, sizeof (v4name));
1945         memset (&v4peer, 0, sizeof (v4peer));
1946         memset (&v6name, 0, sizeof (v6name));
1947         v4name.sin_family  = AF_INET ;
1948         v4peer.sin_family  = AF_INET ;
1949         v6name.sin6_family = AF_INET6;
1950         // Fixed public server data, IPv4 and UDP:
1951         v4server = SERVER_6BED4_IPV4_TXT;
1952         v4peer.sin_addr.s_addr = htonl (SERVER_6BED4_IPV4_INT32);
1953         v4name.sin_port = htons (UDP_PORT_6BED4);
1954         v4peer.sin_port = htons (UDP_PORT_6BED4);
1955         memcpy (&v4listen, &v4peer.sin_addr, 4);
1956         memset (&v4bind, 0, sizeof (v4bind));
1957         v4bind.sin_family = AF_INET;
1958 #ifndef PEER_USE_TAP
1959         v4tunpi6.flags = 0;
1960         v4tunpi6.proto = htons (ETH_P_IPV6);
1961 #endif
1962         //
1963         // Parse commandline arguments
1964         openlog (program, LOG_NDELAY | LOG_PID | LOG_PERROR, LOG_DAEMON);
1965         if (!process_args (argc, argv)) {
1966                 fprintf (stderr, "Argument processing failed\n");
1967                 exit (1);
1968         }
1969         if (!log_to_stderr) {
1970                 closelog ();
1971                 openlog (program, LOG_NDELAY | LOG_PID, LOG_DAEMON);
1972         }
1973         //
1974         // Construct the 6bed4 Router's complete link-layer address
1975         router_linklocal_address_complete [8] = (ntohs (v4peer.sin_port) & 0xff) ^ 0x02;
1976         router_linklocal_address_complete [9] = ntohs (v4peer.sin_port) >> 8;
1977         router_linklocal_address_complete [10] = ntohl (v4peer.sin_addr.s_addr) >> 24;
1978         router_linklocal_address_complete [11] = 0xff;
1979         router_linklocal_address_complete [12] = 0xfe;
1980         memcpy (router_linklocal_address_complete + 13, &((uint8_t *) &v4peer.sin_addr) [1], 3);
1981         //
1982         // Create memory for the freequeue buffer
1983         freequeue = calloc (freequeue_items, sizeof (struct ndqueue));
1984         if (!freequeue) {
1985                 syslog (LOG_CRIT, "%s: Failed to allocate %d queue items\n", program, freequeue_items);
1986                 exit (1);
1987         }
1988         int i;
1989         for (i = 1; i < freequeue_items; i++) {
1990                 freequeue [i].next = &freequeue [i-1];
1991         }
1992         freequeue = &freequeue [freequeue_items - 1];
1993         //
1994         // Create socket for normal outgoing (and return) 6bed4 traffic
1995         if (v4sox == -1) {
1996                 v4sox = socket (AF_INET, SOCK_DGRAM, 0);
1997                 if (v4sox == -1) {
1998                         syslog (LOG_CRIT, "%s: Failed to open a local IPv4 socket -- does your system still support IPv4?\n", program);
1999                         exit (1);
2000                 }
2001         }
2002         struct sockaddr_in tmpaddr;
2003         memset (&tmpaddr, 0, sizeof (tmpaddr));
2004         tmpaddr.sin_family = AF_INET;
2005         srand (getpid ());
2006         uint16_t portn = rand () & 0x3ffe;
2007         uint16_t port0 = portn + 16384;
2008         //TODO// Move port iteration + allocation to separate function
2009         while (portn < port0) {
2010                 tmpaddr.sin_port = htons ((portn & 0x3ffe) + 49152);
2011                 if (bind (v4sox, (struct sockaddr *) &tmpaddr, sizeof (tmpaddr)) == 0) {
2012                         break;
2013                 }
2014                 portn += 2;
2015         }
2016         if (portn < port0) {
2017                 syslog (LOG_DEBUG, "Bound to UDP port %d\n", ntohs (tmpaddr.sin_port));
2018         } else {
2019                 fprintf (stderr, "%s: All even dynamic ports rejected binding: %s\n", program, strerror (errno));
2020                 exit (1);
2021         }
2022         //
2023         // Setup fragmentation, QoS and TTL options
2024         u_int yes = 1;
2025         u_int no = 0;
2026 #if defined(IP_DONTFRAG)
2027         if (setsockopt (v4sox, IPPROTO_IP, IP_DONTFRAG, no, sizeof (no)) == -1) {
2028                 syslog (LOG_ERR, "Failed to permit fragmentation -- not all peers may be accessible with MTU 1280");
2029         }
2030 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2031         int pmtuflag = IP_PMTUDISC_DONT;
2032         if (setsockopt (v4sox, IP_MTU_DISCOVER, IP_MTU_DISCOVER, &pmtuflag, sizeof (pmtuflag)) == -1) {
2033                 syslog (LOG_ERR, "Failed to permit fragmentation -- not all peers may be accessible with MTU 1280");
2034         }
2035 #else
2036 #warning "Target system lacks support for controlling packet fragmentation"
2037 #endif
2038         socklen_t soxlen = sizeof (v4qos);
2039         if (getsockopt (v4sox, IPPROTO_IP, IP_TOS, &v4qos, &soxlen) == -1) {
2040                 syslog (LOG_ERR, "Quality of Service is not supported by the IPv4-side socket");
2041                 v4qos = 0;
2042         }
2043         v6tc = htonl (v4qos << 20);
2044         soxlen = sizeof (v4ttl);
2045         if (getsockopt (v4sox, IPPROTO_IP, IP_TTL, &v4ttl, &soxlen) == -1) {
2046                 syslog (LOG_ERR, "Time To Live cannot be varied on the IPv4 socket");
2047                 v4ttl = 64;
2048         }
2049         //
2050         // Bind to the IPv4 all-nodes local multicast address
2051         memset (&v4allnodes, 0, sizeof (v4allnodes));
2052         v4allnodes.sin_family = AF_INET;
2053         v4allnodes.sin_port = htons (UDP_PORT_6BED4);
2054         v4allnodes.sin_addr.s_addr = htonl ( INADDR_ANY );
2055         if (multicast) {
2056                 v4mcast = socket (AF_INET, SOCK_DGRAM, 0);
2057                 if (v4mcast != -1) {
2058                         struct ip_mreq mreq;
2059                         mreq.imr_multiaddr.s_addr = htonl ( (224L << 24) | 1L);
2060                         mreq.imr_multiaddr.s_addr = htonl ( INADDR_ANY );
2061                         if (bind (v4mcast, (struct sockaddr *) &v4allnodes, sizeof (v4allnodes)) != 0) {
2062                                 close (v4mcast);
2063                                 v4mcast = -1;
2064                                 syslog (LOG_ERR, "No LAN bypass: Failed to bind to IPv4 all-nodes: %s\n", strerror (errno));
2065                         } else if (setsockopt (v4mcast, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (yes)) == -1) {
2066                                 close (v4mcast);
2067                                 v4mcast = -1;
2068                                 syslog (LOG_ERR, "No LAN bypass: Failed to share multicast port: %s\n", strerror (errno));
2069                         } else if (setsockopt (v4mcast, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof (mreq)) == -1) {
2070                                 close (v4mcast);
2071                                 v4mcast = -1;
2072                                 syslog (LOG_ERR, "No LAN bypass: Failed to setup multicast: %s\n", strerror (errno));
2073                         } else if ((v4ttl_mcast != -1) && (setsockopt (v4mcast, IPPROTO_IP, IP_MULTICAST_TTL, &v4ttl_mcast, sizeof (v4ttl_mcast)) == -1)) {
2074                                 close (v4mcast);
2075                                 v4mcast = -1;
2076                                 syslog (LOG_ERR, "No LAN bypass: Failed to configure the multicast radius: %s\n", strerror (errno));
2077                         }
2078 #if 0
2079                         if (bind (v4mcast, (struct sockaddr *) &v4allnodes, sizeof (v4allnodes)) != 0) {
2080                                 close (v4mcast);
2081                                 v4mcast = -1;
2082                                 syslog (LOG_ERR, "%s: No LAN bypass: Failed to bind to IPv4 all-nodes\n", program);
2083                         } else if (listen (v4mcast, 10) != 0) {
2084                                 close (v4mcast);
2085                                 v4mcast = -1;
2086                                 syslog (LOG_ERR, "%s: No LAN bypass: Failed to listen to IPv4 all-nodes\n", program);
2087                         }
2088 #endif
2089                 }
2090         } else {
2091                 syslog (LOG_INFO, "%s: No LAN bypass: Not desired\n", program);
2092         }
2093         //
2094         // Construct an rtnetlink socket for neighbor cache interaction
2095         rtsox = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
2096         if (rtsox == -1) {
2097                 syslog (LOG_CRIT, "Failed to gain access to the neighbor cache: %s\n", strerror (errno));
2098                 exit (1);
2099         }
2100         memset (&rtname,   0, sizeof (rtname  ));
2101         memset (&rtkernel, 0, sizeof (rtkernel));
2102         rtname.nl_family = rtkernel.nl_family = AF_NETLINK;
2103         rtname.nl_pid = getpid ();
2104         if (bind (rtsox, (struct sockaddr *) &rtname, sizeof (rtname)) == -1) {
2105                 syslog (LOG_CRIT, "Failed to bind to the neighbor cache socket: %s\n", strerror (errno));
2106                 exit (1);
2107         }
2108         if (connect (rtsox, (struct sockaddr *) &rtkernel, sizeof (rtkernel)) == -1) {
2109                 syslog (LOG_CRIT, "Failed to connect to the neighbor cachr in the kernel; %s\n", strerror (errno));
2110                 exit (1);
2111         }
2112 { uint8_t testll [6];
2113 uint8_t test_address [] = { 0xfe, 0x80, 0,0,0,0,0,0, 0xc2, 0x25, 0x06, 0xff, 0xfe, 0xb0, 0x7e, 0xa6 };
2114 if (lookup_neighbor (test_address, testll)) {
2115 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]);
2116 } else { syslog (LOG_INFO, "Failed to find LL\n"); } }
2117         //
2118         // If port and/or listen arguments were provided, bind to them
2119         if ((v4bind.sin_addr.s_addr != INADDR_ANY) || (v4bind.sin_port != 0)) {
2120                 if (bind (v4sox, (struct sockaddr *) &v4bind, sizeof (v4bind)) != 0) {
2121                         syslog (LOG_CRIT, "%s: Failed to bind to local socket -- did you specify both address and port?\n", program);
2122                         exit (1);
2123                 }
2124         }
2125         //
2126         // Run the daemon
2127         if (foreground) {
2128                 run_daemon ();
2129         } else {
2130                 if (setsid () != -1) {
2131                         syslog (LOG_CRIT, "%s: Failure to detach from parent session: %s\n", program, strerror (errno));
2132                         exit (1);
2133                 }
2134                 switch (fork ()) {
2135                 case -1:
2136                         syslog (LOG_CRIT, "%s: Failure to fork daemon process: %s\n", program, strerror (errno));
2137                         exit (1);
2138                 case 0:
2139                         close (0);
2140                         if (! log_to_stderr) {
2141                                 close (1);
2142                                 close (2);
2143                         }
2144                         run_daemon ();
2145                         break;
2146                 default:
2147                         break;
2148                 }
2149         }
2150         //
2151         // Report successful creation of the daemon
2152         closelog ();
2153         exit (0);
2154 }
2155