6to4: Add 6to4 tunnel support.
[framework/connectivity/connman.git] / src / 6to4.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2011  Nokia Corporation. All rights reserved.
6  *  Copyright (C) Alexey Kuznetsov et al. from iproute2 package.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <net/if.h>
33 #include <linux/ip.h>
34 #include <linux/if_tunnel.h>
35 #include <linux/netlink.h>
36 #include <linux/rtnetlink.h>
37 #include <sys/ioctl.h>
38 #include <unistd.h>
39
40 #include "connman.h"
41 #include <connman/log.h>
42 #include <connman/ipconfig.h>
43
44 static int tunnel_created;
45 static int tunnel_pending;
46 static char *tunnel_ip_address;
47
48 #define NLMSG_TAIL(nmsg) \
49         ((struct rtattr *) (((void *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
50
51 #ifndef IP_DF
52 #define IP_DF           0x4000          /* Flag: "Don't Fragment"       */
53 #endif
54
55 struct rtnl_handle {
56         int                     fd;
57         struct sockaddr_nl      local;
58         struct sockaddr_nl      peer;
59         __u32                   seq;
60         __u32                   dump;
61 };
62
63 static int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
64 {
65         int len = RTA_LENGTH(4);
66         struct rtattr *rta;
67         if (NLMSG_ALIGN(n->nlmsg_len) + len > (unsigned int)maxlen) {
68                 DBG("Error! max allowed bound %d exceeded", maxlen);
69                 return -1;
70         }
71         rta = NLMSG_TAIL(n);
72         rta->rta_type = type;
73         rta->rta_len = len;
74         memcpy(RTA_DATA(rta), &data, 4);
75         n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
76
77         return 0;
78 }
79
80 static int addattr_l(struct nlmsghdr *n, int maxlen, int type,
81                         const void *data, int alen)
82 {
83         int len = RTA_LENGTH(alen);
84         struct rtattr *rta;
85
86         if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) >
87                                         (unsigned int)maxlen) {
88                 DBG("addattr_l message exceeded bound of %d", maxlen);
89                 return -1;
90         }
91         rta = NLMSG_TAIL(n);
92         rta->rta_type = type;
93         rta->rta_len = len;
94         memcpy(RTA_DATA(rta), data, alen);
95         n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
96
97         return 0;
98 }
99
100 static void rtnl_close(struct rtnl_handle *rth)
101 {
102         if (rth->fd >= 0) {
103                 close(rth->fd);
104                 rth->fd = -1;
105         }
106 }
107
108 static int rtnl_open(struct rtnl_handle *rth)
109 {
110         socklen_t addr_len;
111         int sndbuf = 1024;
112
113         memset(rth, 0, sizeof(*rth));
114
115         rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
116         if (rth->fd < 0) {
117                 connman_error("Can not open netlink socket: %s",
118                                                 strerror(errno));
119                 return -1;
120         }
121
122         if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF, &sndbuf,
123                         sizeof(sndbuf)) < 0) {
124                 connman_error("SO_SNDBUF: %s", strerror(errno));
125                 return -1;
126         }
127
128         memset(&rth->local, 0, sizeof(rth->local));
129         rth->local.nl_family = AF_NETLINK;
130         rth->local.nl_groups = 0;
131
132         if (bind(rth->fd, (struct sockaddr *)&rth->local,
133                         sizeof(rth->local)) < 0) {
134                 connman_error("Can not bind netlink socket: %s",
135                                                         strerror(errno));
136                 return -1;
137         }
138         addr_len = sizeof(rth->local);
139         if (getsockname(rth->fd, (struct sockaddr *)&rth->local,
140                                 &addr_len) < 0) {
141                 connman_error("Can not getsockname: %s", strerror(errno));
142                 return -1;
143         }
144         if (addr_len != sizeof(rth->local)) {
145                 connman_error("Wrong address length %d", addr_len);
146                 return -1;
147         }
148         if (rth->local.nl_family != AF_NETLINK) {
149                 connman_error("Wrong address family %d", rth->local.nl_family);
150                 return -1;
151         }
152         rth->seq = time(NULL);
153
154         return 0;
155 }
156
157 static int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n)
158 {
159         struct sockaddr_nl nladdr;
160         struct iovec iov = {
161                 .iov_base = (void *)n,
162                 .iov_len = n->nlmsg_len
163         };
164         struct msghdr msg = {
165                 .msg_name = &nladdr,
166                 .msg_namelen = sizeof(nladdr),
167                 .msg_iov = &iov,
168                 .msg_iovlen = 1,
169         };
170         unsigned seq;
171         int err;
172
173         memset(&nladdr, 0, sizeof(nladdr));
174         nladdr.nl_family = AF_NETLINK;
175
176         n->nlmsg_seq = seq = ++rtnl->seq;
177         n->nlmsg_flags |= NLM_F_ACK;
178
179         err = sendmsg(rtnl->fd, &msg, 0);
180         if (err < 0) {
181                 connman_error("Can not talk to rtnetlink");
182                 return err;
183         }
184
185         return 0;
186 }
187
188 static int tunnel_create(struct in_addr *addr)
189 {
190         struct ip_tunnel_parm p;
191         struct ifreq ifr;
192         int fd = -1;
193         int ret;
194
195         /* ip tunnel add tun6to4 mode sit remote any local 1.2.3.4 ttl 64 */
196
197         memset(&p, 0, sizeof(struct ip_tunnel_parm));
198         memset(&ifr, 0, sizeof(struct ifreq));
199
200         p.iph.version = 4;
201         p.iph.ihl = 5;
202         p.iph.frag_off = htons(IP_DF);
203         p.iph.protocol = IPPROTO_IPV6;
204         p.iph.saddr = addr->s_addr;
205         p.iph.ttl = 64;
206         strncpy(p.name, "tun6to4", IFNAMSIZ);
207
208         strncpy(ifr.ifr_name, "sit0", IFNAMSIZ);
209         ifr.ifr_ifru.ifru_data = (void *)&p;
210         fd = socket(AF_INET, SOCK_DGRAM, 0);
211         ret = ioctl(fd, SIOCADDTUNNEL, &ifr);
212         if (ret)
213                 connman_error("add tunnel %s failed: %s", ifr.ifr_name,
214                                                         strerror(errno));
215         close(fd);
216
217         return ret;
218 }
219
220 static void tunnel_destroy()
221 {
222         struct ip_tunnel_parm p;
223         struct ifreq ifr;
224         int fd = -1;
225         int ret;
226
227         if (tunnel_created == 0)
228                 return;
229
230         /* ip tunnel del tun6to4 */
231
232         memset(&p, 0, sizeof(struct ip_tunnel_parm));
233         memset(&ifr, 0, sizeof(struct ifreq));
234
235         p.iph.version = 4;
236         p.iph.ihl = 5;
237         p.iph.protocol = IPPROTO_IPV6;
238         strncpy(p.name, "tun6to4", IFNAMSIZ);
239
240         strncpy(ifr.ifr_name, "tun6to4", IFNAMSIZ);
241         ifr.ifr_ifru.ifru_data = (void *)&p;
242         fd = socket(AF_INET, SOCK_DGRAM, 0);
243         if (fd < 0) {
244                 connman_error("socket failed: %s", strerror(errno));
245                 return;
246         }
247
248         ret = ioctl(fd, SIOCDELTUNNEL, &ifr);
249         if (ret)
250                 connman_error("del tunnel %s failed: %s", ifr.ifr_name,
251                                                         strerror(errno));
252         else
253                 tunnel_created = 0;
254
255         tunnel_pending = 0;
256         close(fd);
257
258         g_free(tunnel_ip_address);
259         tunnel_ip_address = NULL;
260 }
261
262 static int tunnel_add_route()
263 {
264         struct rtnl_handle rth;
265         struct in6_addr addr6;
266         int index;
267         int ret = 0;
268
269         struct {
270                 struct nlmsghdr n;
271                 struct rtmsg    r;
272                 char            buf[1024];
273         } req;
274
275         /* ip -6 route add ::/0 via ::192.88.99.1 dev tun6to4 metric 1 */
276
277         index = if_nametoindex("tun6to4");
278         if (index == 0) {
279                 DBG("Can not find device tun6to4");
280                 return -1;
281         }
282
283         memset(&req, 0, sizeof(req));
284
285         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
286         req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
287         req.n.nlmsg_type = RTM_NEWROUTE;
288         req.r.rtm_family = AF_INET6;
289         req.r.rtm_table = RT_TABLE_MAIN;
290         req.r.rtm_protocol = RTPROT_BOOT;
291         req.r.rtm_scope = RT_SCOPE_UNIVERSE;
292         req.r.rtm_type = RTN_UNICAST;
293         req.r.rtm_dst_len = 0;
294
295         inet_pton(AF_INET6, "::192.88.99.1", &addr6);
296
297         addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr6.s6_addr, 16);
298         addattr32(&req.n, sizeof(req), RTA_OIF, index);
299         addattr32(&req.n, sizeof(req), RTA_PRIORITY, 1);
300
301         ret = rtnl_open(&rth);
302         if (ret < 0)
303                 goto done;
304
305         ret = rtnl_talk(&rth, &req.n);
306
307 done:
308         rtnl_close(&rth);
309         return ret;
310 }
311
312 static int tunnel_set_addr(unsigned int a, unsigned int b,
313                         unsigned int c, unsigned int d)
314 {
315         struct rtnl_handle rth;
316         struct in6_addr addr6;
317         char *ip6addr;
318         int ret;
319
320         struct {
321                 struct nlmsghdr n;
322                 struct ifaddrmsg ifa;
323                 char buf[256];
324         } req;
325
326         /* ip -6 addr add dev tun6to4 2002:0102:0304::1/64 */
327
328         memset(&req, 0, sizeof(req));
329
330         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
331         req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
332         req.n.nlmsg_type = RTM_NEWADDR;
333         req.ifa.ifa_family = AF_INET6;
334         req.ifa.ifa_prefixlen = 64;
335         req.ifa.ifa_index = if_nametoindex("tun6to4");
336         if (req.ifa.ifa_index == 0) {
337                 connman_error("Can not find device tun6to4");
338                 ret = -1;
339                 goto done;
340         }
341
342         ip6addr = g_strdup_printf("2002:%02x%02x:%02x%02x::1", a, b, c, d);
343         inet_pton(AF_INET6, ip6addr, &addr6);
344         DBG("ipv6 address %s", ip6addr);
345         g_free(ip6addr);
346
347         addattr_l(&req.n, sizeof(req), IFA_LOCAL, &addr6.s6_addr, 16);
348         addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &addr6.s6_addr, 16);
349
350         ret = rtnl_open(&rth);
351         if (ret < 0)
352                 goto done;
353
354         ret = rtnl_talk(&rth, &req.n);
355
356 done:
357         rtnl_close(&rth);
358         return ret;
359 }
360
361 static int init_6to4(struct in_addr *ip4addr)
362 {
363         unsigned int a, b, c, d;
364         in_addr_t addr;
365         int ret;
366
367         DBG("");
368
369         addr = ntohl(ip4addr->s_addr);
370
371         a = (addr & 0xff000000) >> 24;
372         b = (addr & 0x00ff0000) >> 16;
373         c = (addr & 0x0000ff00) >> 8;
374         d = addr & 0x000000ff;
375
376         ret = tunnel_create(ip4addr);
377         if (ret)
378                 return -1;
379
380         tunnel_created = 1;
381
382         ret = connman_inet_setup_tunnel("tun6to4", 1472);
383         if (ret)
384                 goto error;
385
386         ret = tunnel_set_addr(a, b, c, d);
387         if (ret)
388                 goto error;
389
390         ret = tunnel_add_route();
391         if (ret)
392                 goto error;
393
394         tunnel_pending = 0;
395         return 0;
396
397 error:
398         tunnel_destroy();
399         return -1;
400 }
401
402 static void receive_rs_reply(struct nd_router_advert *reply, void *user_data)
403 {
404         char *address = user_data;
405         struct in_addr ip4addr;
406
407         DBG("reply %p address %s", reply, address);
408
409         /* We try to create tunnel if autoconfiguration did not work i.e.,
410          * we did not receive any reply to router solicitation message.
411          */
412         if (reply == NULL && inet_aton(address, &ip4addr) != 0)
413                 init_6to4(&ip4addr);
414
415         g_free(address);
416 }
417
418 int __connman_6to4_probe(struct connman_service *service)
419 {
420         struct connman_ipconfig *ip4config, *ip6config;
421         enum connman_ipconfig_method method;
422         unsigned int a, b, c, d;
423         struct in_addr ip4addr;
424         in_addr_t addr;
425         const char *address;
426         char *ip_address;
427         int index;
428
429         DBG("service %p", service);
430
431         if (tunnel_created || tunnel_pending)
432                 return 0;
433
434         if (service == NULL)
435                 return -1;
436
437         ip4config = __connman_service_get_ip4config(service);
438         if (ip4config == NULL)
439                 return -1;
440
441         ip6config = __connman_service_get_ip6config(service);
442         if (ip6config == NULL)
443                 return -1;
444
445         method = __connman_ipconfig_get_method(ip6config);
446         if (method != CONNMAN_IPCONFIG_METHOD_AUTO)
447                 return -1;
448
449         address = __connman_ipconfig_get_local(ip4config);
450         if (address == NULL)
451                 return -1;
452
453         if (inet_aton(address, &ip4addr) == 0)
454                 return -1;
455
456         addr = ntohl(ip4addr.s_addr);
457
458         a = (addr & 0xff000000) >> 24;
459         b = (addr & 0x00ff0000) >> 16;
460         c = (addr & 0x0000ff00) >> 8;
461         d = addr & 0x000000ff;
462
463         /* 6to4 tunnel is only usable if we have a public IPv4 address */
464         if (a == 10 || (a == 192 && b == 168) ||
465                                         (a == 172 && (b >= 16 && b <= 31)))
466                 return -1;
467
468         index = connman_ipconfig_get_index(ip4config);
469         ip_address = g_strdup(address);
470         tunnel_pending = 1;
471
472         g_free(tunnel_ip_address);
473         tunnel_ip_address = g_strdup(address);
474
475         return __connman_inet_ipv6_send_rs(index, 2, receive_rs_reply,
476                                                         ip_address);
477 }
478
479 void __connman_6to4_remove(struct connman_ipconfig *ip4config)
480 {
481         const char *address;
482
483         DBG("tunnel ip address %s", tunnel_ip_address);
484
485         if (ip4config == NULL)
486                 return;
487
488         address = __connman_ipconfig_get_local(ip4config);
489         if (address == NULL)
490                 return;
491
492         if (g_strcmp0(address, tunnel_ip_address) != 0)
493                 return;
494
495         if (tunnel_created)
496                 tunnel_destroy();
497 }