Fixed a stx err
[6bed4] / 6bed4router.c
1 /* 6bed4/router.c -- traffic forwarding daemon for public TSP service
2  *
3  * This is an implementation of the profile that makes TSP service publicly
4  * usable, that is without authentication.  However to avoid abuse of such
5  * a service, it is not anonymous -- IPv6 addresses contain the IPv4 address
6  * and port.
7  *
8  * This is an implementation of neighbour and router discovery over a
9  * tunnel that packs IPv6 inside UDP/IPv4.  This tunnel mechanism is
10  * targeted specifically at embedded devices that are to function on
11  * any network, including IPv4-only, while being designed as IPv6-only
12  * devices with a fallback to this tunnel.
13  *
14  * Interestingly, as a side-effect of this design the router daemon can be
15  * stateless.  Any further requirements that are stateful are most likely
16  * filtering, and that can be solved in stateful firewall configuration.
17  *
18  * The intention of TSP is to enable IPv4-only hosts to connecto to
19  * IPv6 services; the public TSP profile adds to that the ability to
20  * do it in a temporary manner.
21  *
22  * TODO: Should we translate ICMPv4 --> ICMPv6?
23  *
24  * From: Rick van Rein <rick@openfortress.nl>
25  */
26
27
28 #include <stdlib.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdbool.h>
32
33 #include <errno.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <getopt.h>
37 #include <fcntl.h>
38
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/time.h>
42 #include <sys/select.h>
43 #include <sys/ioctl.h>
44
45 #include <netinet/in.h>
46 #include <netinet/ip.h>
47 #include <netinet/ip6.h>
48 #include <netinet/udp.h>
49 #include <netinet/icmp6.h>
50 #include <arpa/inet.h>
51
52 #include <linux/if.h>
53 #include <linux/if_tun.h>
54 #include <linux/if_ether.h>
55
56
57 /* The following will initially fail, due to an IANA obligation to avoid
58  * default builds with non-standard options.
59  */
60 #include "nonstd.h"
61
62
63 #define MTU 1280
64
65 /*
66  * The HAVE_SETUP_TUNNEL variable is used to determine whether absense of
67  * the -t option leads to an error, or to an attempt to setup the tunnel.
68  * The setup_tunnel() function used for that is defined per platform, such
69  * as for LINUX.  Remember to maintain the manpage's optionality for -t.
70  */
71 #undef HAVE_SETUP_TUNNEL
72
73
74 /* Global variables */
75
76 char *program;
77
78 int v4sox = -1;
79 int v6sox = -1;
80
81 char *v4server = NULL;
82 char *v6server = NULL;
83 char *v6prefix = NULL;
84
85 const uint8_t v6listen_linklocal [16] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
86 uint8_t v6listen_linklocal_complete [16] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
87
88 uint8_t lladdr_6bed4 [6];
89
90 struct sockaddr_in  v4name;
91 struct sockaddr_in6 v6name;
92
93 struct in6_addr v6listen;
94 struct in6_addr v6listen_complete;
95 struct in_addr  v4listen;
96
97
98 struct {
99         struct tun_pi tun;
100         union {
101                 struct {
102                         struct ip6_hdr v6hdr;
103                         uint8_t data [MTU - sizeof (struct ip6_hdr)];
104                 } idata;
105                 struct {
106                         struct ip6_hdr v6hdr;
107                         struct icmp6_hdr v6icmphdr;
108                 } ndata;
109         } udata;
110 } v4data6;
111
112 #define v4tunpi6        ( v4data6.tun)
113 #define v4data          ((uint8_t *) &v4data6.udata)
114 #define v4hdr6          (&v4data6.udata.idata.v6hdr)
115 #define v4src6          (&v4data6.udata.idata.v6hdr.ip6_src)
116 #define v4dst6          (&v4data6.udata.idata.v6hdr.ip6_dst)
117
118 #define v4v6plen        ( v4data6.udata.ndata.v6hdr.ip6_plen)
119 #define v4v6nexthdr     ( v4data6.udata.ndata.v6hdr.ip6_nxt)
120 #define v4v6hoplimit    ( v4data6.udata.ndata.v6hdr.ip6_hops)
121
122 #define v4icmp6         (&v4data6.udata.ndata.v6icmphdr)
123 #define v4v6icmpdata    ( v4data6.udata.ndata.v6icmphdr.icmp6_data8)
124 #define v4v6icmptype    ( v4data6.udata.ndata.v6icmphdr.icmp6_type)
125 #define v4v6icmpcode    ( v4data6.udata.ndata.v6icmphdr.icmp6_code)
126 #define v4v6icmpcksum   ( v4data6.udata.ndata.v6icmphdr.icmp6_cksum)
127
128 #define v4ngbsoltarget  (&v4data6.udata.ndata.v6icmphdr.icmp6_data8 [4])
129
130
131 struct {
132         struct tun_pi tun;
133         union {
134                 uint8_t data [MTU];
135                 struct ip6_hdr v6hdr;
136                 struct icmp6_hdr v6icmp;
137         } udata;
138         uint8_t zero;
139 } v6data6;
140
141 #define v6tuncmd        ( v6data6.tun)
142 #define v6data          ( v6data6.udata.data)
143 #define v6hdr6          (&v6data6.udata.v6hdr)
144 #define v6src6          (&v6data6.udata.v6hdr.ip6_src)
145 #define v6dst6          (&v6data6.udata.v6hdr.ip6_dst)
146 #define v6hoplimit      ( v6data6.udata.v6hdr.ip6_hops)
147
148 #define v6nexthdr       ( v6data6.udata.v6hdr.ip6_nxt)
149 #define v6icmptype      ( v6data6.udata.v6icmp.icmp6_type)
150
151
152 uint8_t router_linklocal_address [] = {
153         0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00,
154 };
155
156 uint8_t democlient_linklocal_address [] = {
157         0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01,
158 };
159
160 uint8_t allnodes_linklocal_address [] = {
161         0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01,
162 };
163
164 uint8_t allrouters_linklocal_address [] = {
165         0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x02,
166 };
167
168 void addr_6bed4(struct in6_addr *dst_ip6, uint8_t *s_addr, int sin_port, int lanip) {
169
170         dst_ip6->s6_addr [8] = s_addr [0] & 0xfc;
171         memcpy (&dst_ip6->s6_addr [9], s_addr + 1, 3);
172         dst_ip6->s6_addr [12] = sin_port >> 8;
173         dst_ip6->s6_addr [13] = sin_port & 0xff;
174         dst_ip6->s6_addr [14] = (s_addr [0] & 0x03) << 6 | lanip >> 8;
175         dst_ip6->s6_addr [15] = lanip & 0xff;
176 }
177
178 /*
179  *
180  * Driver routines
181  *
182  */
183
184 #ifdef LINUX
185 #define HAVE_SETUP_TUNNEL
186 /* Implement the setup_tunnel() command for Linux.
187  * Return 1 on success, 0 on failure.
188  */
189 int setup_tunnel (void) {
190         v6sox = open ("/dev/net/tun", O_RDWR);
191         if (v6sox == -1) {
192                 fprintf (stderr, "%s: Failed to access tunnel driver on /dev/net/tun: %s\n", program, strerror (errno));
193                 return 0;
194         }
195         int ok = 1;
196         struct ifreq ifreq;
197         memset (&ifreq, 0, sizeof (ifreq));
198         strncpy (ifreq.ifr_name, "6bed4", IFNAMSIZ);
199         ifreq.ifr_flags = IFF_TUN;
200         if (ok && (ioctl (v6sox, TUNSETIFF, (void *) &ifreq) == -1)) {
201                 ok = 0;
202         }
203         ifreq.ifr_name [IFNAMSIZ] = 0;
204         char cmd [512+1];
205         snprintf (cmd, 512, "/sbin/ip -6 addr flush dev %s", ifreq.ifr_name);
206         if (ok && system (cmd) != 0) {
207                 ok = 0;
208         }
209         snprintf (cmd, 512, "/sbin/ip addr add fe80::0 dev %s scope link", ifreq.ifr_name);
210         if (ok && system (cmd) != 0) {
211                 ok = 0;
212         }
213         snprintf (cmd, 512, "/sbin/ip -6 addr add %s dev %s", v6prefix, ifreq.ifr_name);
214         if (ok && system (cmd) != 0) {
215                 ok = 0;
216         }
217         snprintf (cmd, 512, "/sbin/ip link set %s up mtu 1280", ifreq.ifr_name);
218         if (ok && system (cmd) != 0) {
219                 ok = 0;
220         }
221         if (!ok) {
222                 close (v6sox);  /* This removes the tunnel interface */
223         }
224         return ok;
225 }
226 #endif /* LINUX */
227
228
229 /*
230  *
231  * Utility functions
232  *
233  */
234
235
236 /* Calculate the ICMPv6 checksum field
237  */
238 uint16_t icmp6_checksum (size_t payloadlen) {
239         uint16_t plenword = htons (payloadlen);
240         uint16_t nxthword = htons (IPPROTO_ICMPV6);
241         uint16_t *area [] = { (uint16_t *) v4src6, (uint16_t *) v4dst6, &plenword, &nxthword, (uint16_t *) v4icmp6, (uint16_t *) v4v6icmpdata };
242         uint8_t areawords [] = { 8, 8, 1, 1, 1, payloadlen/2 - 2 };
243         uint32_t csum = 0;
244         u_int8_t i, j;
245         for (i=0; i < 6; i++) {
246                 for (j=0; j<areawords [i]; j++) {
247                         csum += ntohs (area [i] [j]);
248                 }
249         }
250         csum = (csum & 0xffff) + (csum >> 16);
251         csum = (csum & 0xffff) + (csum >> 16);
252         csum = htons (~csum);
253         return csum;
254 }
255
256
257 /* Send an ICMPv6 reply.  This is constructed at the tunnel end, from
258  * the incoming message.  The parameter indicates how many bytes the
259  * ICMPv6 package counts after the ICMPv6 header.  It must be 4 (mod 8).
260  *
261  * Actions: v4/udp src becomes dest, set v4/udp/v6 src, len, cksum, send.
262  *          v6 dest is provided (usually v4src6) but if it starts with
263  *          0x00,0x00 it will be replaced with allnodes_linklocal_address.
264  */
265 void icmp6_reply (size_t icmp6bodylen, struct in6_addr *dest) {
266         v4v6hoplimit = 255;
267         if ((icmp6bodylen & 0x07) != 4) {
268                 return;   /* illegal length, drop */
269         }
270         v4v6plen = htons (icmp6bodylen + 4);
271         if ((* (uint16_t *) dest) == htons (0x0000)) {
272                 memcpy (v4dst6, allnodes_linklocal_address, 16);
273         } else {
274                 memcpy (v4dst6, dest, 16);
275         }
276         memcpy (v4src6, router_linklocal_address, 16);
277         v4v6icmpcksum = icmp6_checksum (ntohs (v4v6plen));
278         //
279         // Send the message to the IPv4 originator port
280 printf ("Sending ICMPv6-IPv6-UDP-IPv4 to %d.%d.%d.%d:%d, result = %zd\n",
281 ((uint8_t *) &v4name.sin_addr.s_addr) [0],
282 ((uint8_t *) &v4name.sin_addr.s_addr) [1],
283 ((uint8_t *) &v4name.sin_addr.s_addr) [2],
284 ((uint8_t *) &v4name.sin_addr.s_addr) [3],
285 ntohs (v4name.sin_port),
286         sendto (v4sox,
287                         v4data,
288                         sizeof (struct ip6_hdr) + 4 + icmp6bodylen,
289                         MSG_DONTWAIT,
290                         (struct sockaddr *) &v4name, sizeof (v4name)));
291 }
292
293
294 /* Append the current prefix to an ICMPv6 message.  Incoming optidx
295  * and return values signify original and new offset for ICMPv6 options.
296  * The endlife parameter must be set to obtain zero lifetimes, thus
297  * instructing the tunnel client to stop using an invalid prefix.
298  */
299 size_t icmp6_prefix (size_t optidx, uint8_t endlife) {
300         v4v6icmpdata [optidx++] = 3;    // Type
301         v4v6icmpdata [optidx++] = 4;    // Length
302         v4v6icmpdata [optidx++] = 64;   // This is a /64 prefix
303         v4v6icmpdata [optidx++] = 0xc0; // L=1, A=1, Reserved1=0
304         memset (v4v6icmpdata + optidx, endlife? 0x00: 0xff, 8);
305         optidx += 8;
306                                         // Valid Lifetime: Zero / Infinite
307                                         // Preferred Lifetime: Zero / Infinite
308         memset (v4v6icmpdata + optidx, 0, 4);
309         optidx += 4;
310                                         // Reserved2=0
311         memcpy (v4v6icmpdata + optidx + 0, &v6listen, 8);
312         memset (v4v6icmpdata + optidx + 8, 0, 8);
313         optidx += 16;
314         return optidx;
315 }
316
317
318 /*
319  * TODO: DEPRECATED
320  *
321  * Append a Destination Link-Layer Address Option to an ICMPv6
322  * message.  The address is comprised from the remote's UDP port
323  * and IPv4 address, as seen by the router.  They are supplied
324  * in that order, in network byte order.  The resulting address
325  * is 6 bytes, but even though that makes it look like a MAC
326  * address, it really is another beast.
327  * Note that no effort is made in the router to recognise the
328  * "illegal port number" 0x3333 -- the client needs a message
329  * and will recognise it and act on it.
330  */
331 size_t icmp6_dest_linkaddr (size_t optidx) {
332         uint8_t typelen [2] = { ND_OPT_DESTINATION_LINKADDR, 1 };
333         memcpy (v4v6icmpdata + optidx + 0, &typelen, 2);
334         v4v6icmpdata [optidx + 2] = ntohs (v4name.sin_port) & 0xff;
335         v4v6icmpdata [optidx + 3] = ntohs (v4name.sin_port) >> 8;
336         memcpy (v4v6icmpdata + optidx + 4, &v4name.sin_addr, 4);
337         optidx += 8;
338         return optidx;
339 }
340
341
342 /*
343  * Test if an address is a local override.  This function is compiled-in
344  * to support hosts with a /64 from their own ISP and nothing more; they
345  * need to access local IPv6 addresses.  We rely on the 6bed4 port being
346  * 0 to decide that an address cannot be anything but a local override.
347  * Define LOCAL_OVERRIDES_PORT0 to enable this feature.
348  */
349 #ifdef LOCAL_OVERRIDES_PORT0
350 static inline bool is_local_override (struct in6_addr *ip6) {
351         return ip6->s6_addr16 [6] == 0;
352 }
353 #else
354 #define is_local_override(_) false
355 #endif
356
357 /*
358  * Test if the provided IPv6 address matches the prefix used for 6bed4.
359  */
360 static inline bool is_6bed4 (struct in6_addr *ip6) {
361         return memcmp (&v6listen, ip6->s6_addr, 8) == 0;
362 }
363
364
365 /*
366  * Validate the originator's IPv6 address.  It should match the
367  * UDP/IPv4 coordinates of the receiving 6bed4 socket.  Also,
368  * the /64 prefix must match that of v6listen.
369  */
370 bool validate_originator (struct sockaddr_in *sin, struct in6_addr *ip6) {
371         uint16_t port = ntohs (sin->sin_port);
372         uint32_t addr = ntohl (sin->sin_addr.s_addr);
373
374         if (!is_6bed4 (ip6)) {
375                 return false;
376         }
377         if ((port & 0xff) != ip6->s6_addr [13]) {
378                 return false;
379         }
380         if ((port >> 8) != ip6->s6_addr [12]) {
381                 return false;
382         }
383         if (addr != ((ntohl(ip6->s6_addr32 [2]) & 0xfcffffff) | (((uint32_t) ip6->s6_addr [14] & 0xc0) << 18))) {
384                 return false;
385         }
386         return true;
387 }
388
389
390 /*
391  * Major packet processing functions
392  */
393
394
395 /*
396  * Respond to a Router Solicitation received over the 6bed4 Network.
397  */
398 void handle_6bed4_router_solicit (void) {
399         struct in6_addr observed;
400         v4v6icmptype = ND_ROUTER_ADVERT;
401         v4v6icmpdata [0] = 0;                   // Cur Hop Limit: unspec
402         v4v6icmpdata [1] = 0x18;                // M=0, O=0
403                                                 // H=0, Prf=11=Low
404                                                 // Reserved=0
405 // TODO: wire says 0x44 for router_adv.flags
406         size_t writepos = 2;
407         memset (v4v6icmpdata+writepos, 0xff, 2+4+4);
408                                         // Router Lifetime: max, 18.2h
409                                         // Reachable Time: max
410                                         // Retrans Timer: max
411         writepos += 2+4+4;
412         writepos = icmp6_prefix (writepos, 0);
413         //TODO:DEPRECATED// writepos = icmp6_dest_linkaddr (writepos);
414         memcpy (&observed, v6listen_linklocal, 8);
415         addr_6bed4(&observed, (uint8_t *) &v4name.sin_addr.s_addr, ntohs(v4name.sin_port), 1);
416         icmp6_reply (writepos, &observed);
417 }
418
419
420 /* Handle the IPv4 message pointed at by msg as a neighbouring command.
421  *
422  * Type Code    ICMPv6 meaning                  Handling
423  * ---- ----    -----------------------------   ----------------------------
424  * 133  0       Router Solicitation             Send Router Advertisement
425  * 134  0       Router Advertisement            Ignore
426  * 135  0       Neighbour Solicitation          Send Neighbour Advertisement
427  * 136  0       Neighbour Advertisement         Ignore
428  * 137  0       Redirect                        Ignore
429  */
430 void handle_4to6_nd (ssize_t v4ngbcmdlen) {
431         uint16_t srclinklayer;
432         if (v4ngbcmdlen < sizeof (struct ip6_hdr) + sizeof (struct icmp6_hdr)) {
433                 return;
434         }
435         if (v4v6icmpcode != 0) {
436                 return;
437         }
438         if (icmp6_checksum (v4ngbcmdlen - sizeof (struct ip6_hdr)) != v4v6icmpcksum) {
439                 return;
440         }
441         //
442         // Approved.  Perform neighbourly courtesy.
443         switch (v4v6icmptype) {
444         case ND_ROUTER_SOLICIT:
445                 //
446                 // Validate Router Solicitation
447                 srclinklayer = 0;
448                 if (v4ngbcmdlen == sizeof (struct ip6_hdr) + 8 + 8) {
449                         // One option is possible, the source link-layer address
450                         if (v4v6icmpdata [4] != 1 || v4v6icmpdata [5] != 1) {
451                                 break;   /* bad opton, ignore */
452                         }
453                         // The source link-layer address is end-aligned
454                         srclinklayer = (v4v6icmpdata [10] << 8) | v4v6icmpdata [11];
455                         if (srclinklayer == 0) {
456                                 break;   /* illegal, ignore */
457                         }
458                 } else if (v4ngbcmdlen == sizeof (struct ip6_hdr) + 8) {
459                         srclinklayer = 0;   /* set for latter filling */
460                 } else {
461                         break;   /* illegal length, drop */
462                 }
463                 //
464                 // Having accepted the Router Advertisement, respond
465                 handle_6bed4_router_solicit ();
466                 break;
467         case ND_NEIGHBOR_SOLICIT:
468                 //
469                 // Validate Neigbour Solicitation
470                 if (!validate_originator (&v4name, v4src6)) {
471                         break;  /* bad source address, drop */
472                 }
473                 if ((v4ngbcmdlen != sizeof (struct ip6_hdr) + 24) &&
474                     (v4ngbcmdlen != sizeof (struct ip6_hdr) + 24 + 8)) {
475                         break;   /* funny length, drop */
476                 }
477                 if ((memcmp (v4ngbsoltarget, v6listen_linklocal, 16) != 0) &&
478                     (memcmp (v4ngbsoltarget, v6listen_linklocal_complete, 16) != 0) &&
479                     (memcmp (v4ngbsoltarget, &v6listen_complete, 16) != 0)) {
480                         break;  /* target not known here, drop */
481                 }
482                 //
483                 // Construct Neigbour Advertisement
484                 v4v6icmptype = ND_NEIGHBOR_ADVERT;
485                 v4v6icmpdata [0] = 0xc0;
486                 v4v6icmpdata [1] =
487                 v4v6icmpdata [2] =
488                 v4v6icmpdata [3] = 0x00;        // R=1, S=1, O=1, Reserved=0
489                 memcpy (v4v6icmpdata +  4, &v6listen_complete, 16);
490                 // Append option: the target link-layer address
491                 // Note: wire does not include target link-layer address
492                 v4v6icmpdata [20] = 2;          // Type: Target Link-Layer Addr
493                 v4v6icmpdata [21] = 1;          // Length: 1x 8 bytes
494                 memcpy (v4v6icmpdata + 22, lladdr_6bed4, 6);
495                 icmp6_reply (28, v4src6);       // 28 is the ICMPv6 response length
496                 break;
497         case ND_ROUTER_ADVERT:
498         case ND_NEIGHBOR_ADVERT:
499         case ND_REDIRECT:
500                 break;   /* drop */
501         }
502 }
503
504
505 /* 
506  * Forward a message received over the 6bed4 Network over IPv6.
507  * Note that existing checksums will work well, as only the
508  * Hop Limit has been altered, and this is not part of the
509  * checksum calculations.
510  */
511 void handle_4to6_plain_unicast (ssize_t v4datalen) {
512 printf ("Writing IPv6, result = %zd\n",
513         write (v6sox, &v4data6, sizeof (struct tun_pi) + v4datalen));
514 }
515
516
517 /*
518  * Forward a 6bed4 message to another 6bed4 destination address.
519  * Note that existing checksums will work well, as only the
520  * Hop Limit has been altered, and this is not part of the
521  * checksum calculations.
522  */
523 void relay_6bed4_plain_unicast (uint8_t* data, ssize_t v4datalen, struct in6_addr *ip6) {
524         v4name.sin_port = htons (ip6->s6_addr [12] << 8 | ip6->s6_addr [13]);
525         uint8_t *addr = (uint8_t *) &v4name.sin_addr.s_addr;
526         addr [0] = (ip6->s6_addr [8] & 0xfc) | ip6->s6_addr [14] >> 6;
527         memcpy (addr + 1, ip6->s6_addr + 9, 3);
528 printf ("Relaying over 6bed4 Network to %d.%d.%d.%d:%d, result = %zd\n",
529 ((uint8_t *) &v4name.sin_addr.s_addr) [0],
530 ((uint8_t *) &v4name.sin_addr.s_addr) [1],
531 ((uint8_t *) &v4name.sin_addr.s_addr) [2],
532 ((uint8_t *) &v4name.sin_addr.s_addr) [3],
533 ntohs (v4name.sin_port),
534         sendto (v4sox,
535                         data, v4datalen,
536                         MSG_DONTWAIT,
537                         (struct sockaddr *) &v4name, sizeof (v4name)));
538 }
539
540
541 /* Receive a tunnel package, and route it to either the handler for the
542  * tunnel protocol, or to the handler that checks and then unpacks the
543  * contained IPv6.
544  */
545 void handle_4to6 (void) {
546         uint8_t buf [1501];
547         ssize_t buflen;
548         socklen_t adrlen = sizeof (v4name);
549         //
550         // Receive IPv4 package, which may be tunneled or a tunnel request
551         buflen = recvfrom (v4sox,
552                         v4data, MTU,
553                         MSG_DONTWAIT,
554                         (struct sockaddr *) &v4name, &adrlen
555                 );
556         if (buflen == -1) {
557                 printf ("%s: Error receiving IPv4-side package: %s",
558                                 program, strerror (errno));
559                 return;
560         }
561         if (buflen < sizeof (struct ip6_hdr)) {
562                 return;
563         }
564         if ((v4data [0] & 0xf0) != 0x60) {
565                 // Not an IPv6 packet
566                 return;
567         }
568         //
569         // Handle the tunneled IPv6 package (dependent on its class)
570         if ((v4v6nexthdr == IPPROTO_ICMPV6) &&
571                         (v4v6icmptype >= 133) && (v4v6icmptype <= 137)) {
572                 //
573                 // Not Plain: Router Adv/Sol, Neighbor Adv/Sol, Redirect
574                 if (v4v6hoplimit != 255) {
575                         return;
576                 }
577                 handle_4to6_nd (buflen);
578         } else if ((v4dst6->s6_addr [0] != 0xff) && !(v4dst6->s6_addr [8] & 0x01)) {
579                 //
580                 // Plain Unicast
581                 if (is_local_override (v4dst6)) {
582                         handle_4to6_plain_unicast (buflen);
583                 } else if (validate_originator (&v4name, v4src6)) {
584                         if (v4v6hoplimit-- <= 1) {
585                                 return;
586                         }
587                         if (is_6bed4 (v4dst6)) {
588                                 relay_6bed4_plain_unicast (v4data, buflen, v4dst6);
589                         } else {
590                                 handle_4to6_plain_unicast (buflen);
591                         }
592                 } else if (is_6bed4 (v4src6)) {
593                         // The sender must not have kept NAT/firewall holes
594                         // open and should be instructed about a change in
595                         // its 6bed4 Link-Local Address.
596                         handle_6bed4_router_solicit ();
597                 }
598         } else {
599                 //
600                 // Plain Multicast
601                 //OPTIONAL// validate_originator, hoplimit, relay_mcast.
602                 return;
603         }
604 }
605
606
607 /* Receive an IPv6 package, check its address and pickup IPv4 address and
608  * port, then package it as a tunnel message and forward it to IPv4:port.
609  */
610 void handle_6to4 (void) {
611         //
612         // Receive the IPv6 package and ensure a consistent size
613         size_t rawlen = read (v6sox, &v6data6, sizeof (v6data6));
614         if (rawlen == -1) {
615                 return;         /* error reading, drop */
616         }
617         if (rawlen < sizeof (struct tun_pi) + sizeof (struct ip6_hdr) + 1) {
618                 return;         /* too small, drop */
619         }
620         if (v6tuncmd.proto != htons (ETH_P_IPV6)) {
621                 return;         /* no IPv6, drop */
622         }
623         if ((v6nexthdr == IPPROTO_ICMPV6) &&
624                         (v6icmptype >= 133) && (v6icmptype <= 137)) {
625                 return;         /* not plain IPv6, drop */
626         }
627         if (v6hoplimit-- <= 1) {
628                 // TODO: Send back an ICMPv6 error message
629                 return;         /* hop limit exceeded, drop */
630         }
631         if ((v6dst6->s6_addr [0] == 0xff) /* TODO:UDP_PORT_NOT_YET_FORCED_TO_EVEN || (v6dst6->s6_addr [8] & 0x01) */ ) {
632 printf ("Received multicast IPv6 data, flags=0x%04x, proto=0x%04x\n", v6tuncmd.flags, v6tuncmd.proto);
633                 //OPTIONAL// handle_6to4_plain_multicast ()
634                 return;         /* multicast, drop */
635         }
636 printf ("Received plain unicast IPv6 data, flags=0x%04x, proto=0x%04x\n", v6tuncmd.flags, v6tuncmd.proto);
637         //
638         // Ensure that the incoming IPv6 address is properly formatted
639         // Note that this avoids access to ::1/128, fe80::/10, fec0::/10
640         if (memcmp (v6dst6, &v6listen, 8) != 0) {
641                 return;
642         }
643         //
644         // Harvest socket address data from destination IPv6, then send
645         relay_6bed4_plain_unicast (v6data, rawlen - sizeof (struct tun_pi), v6dst6);
646 }
647
648
649 /* Run the daemon core code, passing information between IPv4 and IPv6 and
650  * responding to tunnel requests if so requested.
651  */
652 void run_daemon (void) {
653         fd_set io;
654         FD_ZERO (&io);
655         FD_SET (v4sox, &io);
656         FD_SET (v6sox, &io);
657         int nfds = (v4sox < v6sox)? (v6sox + 1): (v4sox + 1);
658         while (1) {
659                 select (nfds, &io, NULL, NULL, NULL);
660                 if (FD_ISSET (v4sox, &io)) {
661                         handle_4to6 ();
662                 } else {
663                         FD_SET (v4sox, &io);
664                 }
665                 if (FD_ISSET (v6sox, &io)) {
666                         handle_6to4 ();
667                 } else {
668                         FD_SET (v6sox, &io);
669                 }
670 fflush (stdout);
671         }
672 }
673
674
675 /* Option descriptive data structures */
676
677 char *short_opt = "l:L:t:h";
678
679 struct option long_opt [] = {
680         { "v4listen", 1, NULL, 'l' },
681         { "v6prefix", 1, NULL, 'L' },
682         { "tundev", 1, NULL, 't' },
683         { "help", 0, NULL, 'h' },
684         { NULL, 0, NULL, 0 }    /* Array termination */
685 };
686
687 /* Parse commandline arguments (and start to process them).
688  * Return 1 on success, 0 on failure.
689  */
690 int process_args (int argc, char *argv []) {
691         int ok = 1;
692         int help = (argc == 1);
693         int done = 0;
694         while (!done) {
695                 switch (getopt_long (argc, argv, short_opt, long_opt, NULL)) {
696                 case -1:
697                         done = 1;
698                         if (optind != argc) {
699                                 fprintf (stderr, "%s: Extra arguments not permitted: %s...\n", program, argv [optind]);
700                                 ok = 0;
701                         }
702                         break;
703                 case 'l':
704                         if (v4sox != -1) {
705                                 ok = 0;
706                                 fprintf (stderr, "%s: Only one -l argument is permitted\n", program);
707                                 break;
708                         }
709                         v4server = optarg;
710                         if (inet_pton (AF_INET, optarg, &v4name.sin_addr) <= 0) {
711                                 ok = 0;
712                                 fprintf (stderr, "%s: Failed to parse IPv4 address %s\n", program, optarg);
713                                 break;
714                         }
715                         memcpy (&v4listen, &v4name.sin_addr, 4);
716                         v4sox = socket (AF_INET, SOCK_DGRAM, 0);
717                         if (v4sox == -1) {
718                                 ok = 0;
719                                 fprintf (stderr, "%s: Failed to allocate UDPv4 socket: %s\n", program, strerror (errno));
720                                 break;
721                         }
722                         if (bind (v4sox, (struct sockaddr *) &v4name, sizeof (v4name)) != 0) {
723                                 ok = 0;
724                                 fprintf (stderr, "%s: Failed to bind to UDPv4 %s:%d: %s\n", program, optarg, ntohs (v4name.sin_port), strerror (errno));
725                                 break;
726                         }
727                         break;
728                 case 'L':
729                         if (v6server) {
730                                 ok = 0;
731                                 fprintf (stderr, "%s: Only one -L argument is permitted\n", program);
732                                 break;
733                         }
734                         char *slash64 = strchr (optarg, '/');
735                         if (!slash64 || strcmp (slash64, "/64") != 0) {
736                                 ok = 0;
737                                 fprintf (stderr, "%s: The -L argument must be an explicit /64 prefix and not %s\n", program, slash64? slash64: "implied");
738                                 break;
739                         }
740                         *slash64 = 0;
741                         v6server = strdup (optarg);
742                         *slash64 = '/';
743                         v6prefix = optarg;
744                         if (!v6server || inet_pton (AF_INET6, v6server, &v6listen) <= 0) {
745                                 ok = 0;
746                                 fprintf (stderr, "%s: Failed to parse IPv6 prefix %s\n", program, optarg);
747                                 break;
748                         }
749                         if (v6listen.s6_addr32 [2] || v6listen.s6_addr32 [3]) {
750                                 ok = 0;
751                                 fprintf (stderr, "%s: IPv6 prefix contains bits beyond its /64 prefix: %s\n", program, optarg);
752                                 break;
753                         }
754                         break;
755                 case 't':
756                         if (v6sox != -1) {
757                                 ok = 0;
758                                 fprintf (stderr, "%s: Multiple -t arguments are not permitted\n", program);
759                                 break;
760                         }
761                         v6sox = open (optarg, O_RDWR);
762                         if (v6sox == -1) {
763                                 ok = 0;
764                                 fprintf (stderr, "%s: Failed to open tunnel device %s: %s\n", program, optarg, strerror (errno));
765                                 break;
766                         }
767                         break;
768                 default:
769                         ok = 0;
770                         help = 1;
771                         /* continue into 'h' to produce usage information */
772                 case 'h':
773                         help = 1;
774                         break;
775                 }
776                 if (help || !ok) {
777                         done = 1;
778                 }
779         }
780         if (help) {
781 #ifdef HAVE_SETUP_TUNNEL
782                 fprintf (stderr, "Usage: %s [-t /dev/tunX] -l <v4server> -L <v6prefix>/64\n       %s -h\n", program, program);
783 #else
784                 fprintf (stderr, "Usage: %s -t /dev/tunX -l <v4server> -L <v6prefix>/64\n       %s -h\n", program, program);
785 #endif
786                 return ok;
787         }
788         if (!ok) {
789                 return 0;
790         }
791         if (v4sox == -1) {
792                 fprintf (stderr, "%s: Use -l to specify an IPv4 address for the tunnel interface\n", program);
793                 return 0;
794         }
795         if (!v6server) {
796                 fprintf (stderr, "%s: Use -L to specify a /64 prefix on the IPv6 side\n", program);
797                 return 0;
798         }
799 #ifdef HAVE_SETUP_TUNNEL
800         if (v6sox == -1) {
801                 if (geteuid () != 0) {
802                         fprintf (stderr, "%s: You should be root, or use -t to specify an accessible tunnel device\n", program);
803                         return 0;
804                 }
805                 ok = setup_tunnel ();
806         }
807 #else /* ! HAVE_SETUP_TUNNEL */
808         if (v6sox == -1) {
809                 fprintf (stderr, "%s: You must specify a tunnel device with -t that is accessible to you\n", program);
810                 return 0;
811         }
812 #endif /* HAVE_SETUP_TUNNEL */
813         return ok;
814 }
815
816
817 /* The main program parses commandline arguments and forks off the daemon
818  */
819 int main (int argc, char *argv []) {
820         //
821         // Initialise
822         program = argv [0];
823         memset (&v4name, 0, sizeof (v4name));
824         memset (&v6name, 0, sizeof (v6name));
825         v4name.sin_family  = AF_INET ;
826         v6name.sin6_family = AF_INET6;
827         v4name.sin_port = htons (UDP_PORT_6BED4);   /* 6BED4 standard port */
828         v4tunpi6.flags = 0;
829         v4tunpi6.proto = htons (ETH_P_IPV6);
830         //
831         // Parse commandline arguments
832         if (!process_args (argc, argv)) {
833                 exit (1);
834         }
835         //
836         // Setup a few addresses for later comparison/reproduction
837         //  * lladdr_6bed4 is the 6bed4 Link-Local Address
838         //  * v6listen_complete is the router's full IPv6 address (with if-id)
839         //  * v6listen_linklocal_complete is fe80::/64 plus the router's if-id
840         // A few others have already been setup at this time
841         //  * v6listen is the router's 6bed4 prefix ending in 64 zero bits
842         //  * v6listen_linklocal is the address fe80::/128
843         //
844         lladdr_6bed4 [0] = UDP_PORT_6BED4 & 0xff;
845         lladdr_6bed4 [1] = UDP_PORT_6BED4 >> 8;
846         memcpy (lladdr_6bed4 + 2, (uint8_t *) &v4name.sin_addr, 4);
847         memcpy (&v6listen_complete, &v6listen, 8);
848         addr_6bed4(&v6listen_complete, lladdr_6bed4 + 2, ntohs(v4name.sin_port), 0);
849
850         memcpy (v6listen_linklocal_complete, v6listen_linklocal, 8);
851         memcpy (v6listen_linklocal_complete + 8, &v6listen_complete.s6_addr [8], 8);
852 printf ("LISTEN lladdr_6bed4 = %02x:%02x:%02x:%02x:%02x:%02x\n", lladdr_6bed4 [0], lladdr_6bed4 [1], lladdr_6bed4 [2], lladdr_6bed4 [3], lladdr_6bed4 [4], lladdr_6bed4 [5]);
853 printf ("LISTEN v6listen = %x:%x:%x:%x:%x:%x:%x:%x\n", htons (v6listen.s6_addr16 [0]), htons (v6listen.s6_addr16 [1]), htons (v6listen.s6_addr16 [2]), htons (v6listen.s6_addr16 [3]), htons (v6listen.s6_addr16 [4]), htons (v6listen.s6_addr16 [5]), htons (v6listen.s6_addr16 [6]), htons (v6listen.s6_addr16 [7]));
854 printf ("LISTEN v6listen_complete = %x:%x:%x:%x:%x:%x:%x:%x\n", htons (v6listen_complete.s6_addr16 [0]), htons (v6listen_complete.s6_addr16 [1]), htons (v6listen_complete.s6_addr16 [2]), htons (v6listen_complete.s6_addr16 [3]), htons (v6listen_complete.s6_addr16 [4]), htons (v6listen_complete.s6_addr16 [5]), htons (v6listen_complete.s6_addr16 [6]), htons (v6listen_complete.s6_addr16 [7]));
855 printf ("LISTEN v6listen_linklocal = %x:%x:%x:%x:%x:%x:%x:%x\n", htons (((uint16_t *) v6listen_linklocal) [0]), htons (((uint16_t *) v6listen_linklocal) [1]), htons (((uint16_t *) v6listen_linklocal) [2]), htons (((uint16_t *) v6listen_linklocal) [3]), htons (((uint16_t *) v6listen_linklocal) [4]), htons (((uint16_t *) v6listen_linklocal) [5]), htons (((uint16_t *) v6listen_linklocal) [6]), htons (((uint16_t *) v6listen_linklocal) [7]));
856 printf ("LISTEN v6listen_linklocal_complete = %x:%x:%x:%x:%x:%x:%x:%x\n", htons (((uint16_t *) v6listen_linklocal_complete) [0]), htons (((uint16_t *) v6listen_linklocal_complete) [1]), htons (((uint16_t *) v6listen_linklocal_complete) [2]), htons (((uint16_t *) v6listen_linklocal_complete) [3]), htons (((uint16_t *) v6listen_linklocal_complete) [4]), htons (((uint16_t *) v6listen_linklocal_complete) [5]), htons (((uint16_t *) v6listen_linklocal_complete) [6]), htons (((uint16_t *) v6listen_linklocal_complete) [7]));
857         //
858         // Start the main daemon process
859 #ifdef SKIP_TESTING_KLUDGE_IN_FOREGROUND
860         switch (fork ()) {
861         case -1:                /* Error forking */
862                 fprintf (stderr, "%s: Failed to fork: %s\n", program, strerror (errno));
863                 exit (1);
864         case 0:                 /* Child process */
865                 close (0);
866                 //TODO: tmp.support for ^printf// close (1);
867                 close (2);
868                 setsid ();
869                 run_daemon ();
870                 break;
871         default:                /* Parent process */
872                 close (v4sox);
873                 close (v6sox);
874                 break;
875         }
876 #else
877         run_daemon ();
878 #endif
879         //
880         // Report successful creation of the daemon
881         return 0;
882 }