dhcpv6: Initial stateful DHCPv6 support.
[platform/upstream/connman.git] / gdhcp / common.c
1 /*
2  *  DHCP library with GLib integration
3  *
4  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License version 2 as
8  *  published by the Free Software Foundation.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <sys/ioctl.h>
30 #include <stdint.h>
31 #include <string.h>
32 #include <endian.h>
33 #include <net/if_arp.h>
34 #include <linux/if.h>
35 #include <netpacket/packet.h>
36 #include <net/ethernet.h>
37 #include <arpa/inet.h>
38
39 #include <inet.h>
40
41 #include "gdhcp.h"
42 #include "common.h"
43
44 static const DHCPOption client_options[] = {
45         { OPTION_IP,                    0x01 }, /* subnet-mask */
46         { OPTION_IP | OPTION_LIST,      0x03 }, /* routers */
47         { OPTION_IP | OPTION_LIST,      0x06 }, /* domain-name-servers */
48         { OPTION_STRING,                0x0c }, /* hostname */
49         { OPTION_STRING,                0x0f }, /* domain-name */
50         { OPTION_IP | OPTION_LIST,      0x2a }, /* ntp-servers */
51         { OPTION_U32,                   0x33 }, /* dhcp-lease-time */
52         /* Options below will not be exposed to user */
53         { OPTION_IP,                    0x32 }, /* requested-ip */
54         { OPTION_U8,                    0x35 }, /* message-type */
55         { OPTION_U32,                   0x36 }, /* server-id */
56         { OPTION_U16,                   0x39 }, /* max-size */
57         { OPTION_STRING,                0x3c }, /* vendor */
58         { OPTION_STRING,                0x3d }, /* client-id */
59         { OPTION_STRING,                0xfc }, /* UNOFFICIAL proxy-pac */
60         { OPTION_UNKNOWN,               0x00 },
61 };
62
63 GDHCPOptionType dhcp_get_code_type(uint8_t code)
64 {
65         int i;
66
67         for (i = 0; client_options[i].code; i++) {
68                 if (client_options[i].code == code)
69                         return client_options[i].type;
70         }
71
72         return OPTION_UNKNOWN;
73 }
74
75 uint8_t *dhcp_get_option(struct dhcp_packet *packet, int code)
76 {
77         int len, rem;
78         uint8_t *optionptr;
79         uint8_t overload = 0;
80
81         /* option bytes: [code][len][data1][data2]..[dataLEN] */
82         optionptr = packet->options;
83         rem = sizeof(packet->options);
84
85         while (1) {
86                 if (rem <= 0)
87                         /* Bad packet, malformed option field */
88                         return NULL;
89
90                 if (optionptr[OPT_CODE] == DHCP_PADDING) {
91                         rem--;
92                         optionptr++;
93
94                         continue;
95                 }
96
97                 if (optionptr[OPT_CODE] == DHCP_END) {
98                         if (overload & FILE_FIELD) {
99                                 overload &= ~FILE_FIELD;
100
101                                 optionptr = packet->file;
102                                 rem = sizeof(packet->file);
103
104                                 continue;
105                         } else if (overload & SNAME_FIELD) {
106                                 overload &= ~SNAME_FIELD;
107
108                                 optionptr = packet->sname;
109                                 rem = sizeof(packet->sname);
110
111                                 continue;
112                         }
113
114                         break;
115                 }
116
117                 len = 2 + optionptr[OPT_LEN];
118
119                 rem -= len;
120                 if (rem < 0)
121                         continue; /* complain and return NULL */
122
123                 if (optionptr[OPT_CODE] == code)
124                         return optionptr + OPT_DATA;
125
126                 if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD)
127                         overload |= optionptr[OPT_DATA];
128
129                 optionptr += len;
130         }
131
132         return NULL;
133 }
134
135 int dhcp_end_option(uint8_t *optionptr)
136 {
137         int i = 0;
138
139         while (optionptr[i] != DHCP_END) {
140                 if (optionptr[i] != DHCP_PADDING)
141                         i += optionptr[i + OPT_LEN] + OPT_DATA - 1;
142
143                 i++;
144         }
145
146         return i;
147 }
148
149 uint8_t *dhcpv6_get_option(struct dhcpv6_packet *packet, uint16_t pkt_len,
150                         int code, uint16_t *option_len, int *option_count)
151 {
152         int rem, count = 0;
153         uint8_t *optionptr, *found = NULL;
154         uint16_t opt_code, opt_len, len;
155
156         optionptr = packet->options;
157         rem = pkt_len - 1 - 3;
158
159         if (rem <= 0)
160                 /* Bad packet */
161                 return NULL;
162
163         while (1) {
164                 opt_code = optionptr[0] << 8 | optionptr[1];
165                 opt_len = len = optionptr[2] << 8 | optionptr[3];
166                 len += 2 + 2; /* skip code and len */
167
168                 rem -= len;
169                 if (rem < 0)
170                         break;
171
172                 if (opt_code == code) {
173                         if (option_len != NULL)
174                                 *option_len = opt_len;
175                         found = optionptr + 2 + 2;
176                         count++;
177                 }
178
179                 if (rem == 0)
180                         break;
181
182                 optionptr += len;
183         }
184
185         if (option_count != NULL)
186                 *option_count = count;
187
188         return found;
189 }
190
191 uint8_t *dhcpv6_get_sub_option(unsigned char *option, uint16_t max_len,
192                         uint16_t *option_code, uint16_t *option_len)
193 {
194         int rem;
195         uint16_t code, len;
196
197         rem = max_len - 2 - 2;
198
199         if (rem <= 0)
200                 /* Bad option */
201                 return NULL;
202
203         code = option[0] << 8 | option[1];
204         len = option[2] << 8 | option[3];
205
206         rem -= len;
207         if (rem < 0)
208                 return NULL;
209
210         *option_code = code;
211         *option_len = len;
212
213         return &option[4];
214 }
215
216 /*
217  * Add an option (supplied in binary form) to the options.
218  * Option format: [code][len][data1][data2]..[dataLEN]
219  */
220 void dhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt)
221 {
222         unsigned len;
223         uint8_t *optionptr = packet->options;
224         unsigned end = dhcp_end_option(optionptr);
225
226         len = OPT_DATA + addopt[OPT_LEN];
227
228         /* end position + (option code/length + addopt length) + end option */
229         if (end + len + 1 >= DHCP_OPTIONS_BUFSIZE)
230                 /* option did not fit into the packet */
231                 return;
232
233         memcpy(optionptr + end, addopt, len);
234
235         optionptr[end + len] = DHCP_END;
236 }
237
238 /*
239  * Add an option (supplied in binary form) to the options.
240  * Option format: [code][len][data1][data2]..[dataLEN]
241  */
242 void dhcpv6_add_binary_option(struct dhcpv6_packet *packet, uint16_t max_len,
243                                 uint16_t *pkt_len, uint8_t *addopt)
244 {
245         unsigned len;
246         uint8_t *optionptr = packet->options;
247
248         len = 2 + 2 + (addopt[2] << 8 | addopt[3]);
249
250         /* end position + (option code/length + addopt length) */
251         if (*pkt_len + len >= max_len)
252                 /* option did not fit into the packet */
253                 return;
254
255         memcpy(optionptr + *pkt_len, addopt, len);
256         *pkt_len += len;
257 }
258
259 void dhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code,
260                                                         uint32_t data)
261 {
262         uint8_t option[6], len;
263         GDHCPOptionType type = dhcp_get_code_type(code);
264
265         if (type == OPTION_UNKNOWN)
266                 return;
267
268         option[OPT_CODE] = code;
269
270         len = dhcp_option_lengths[type & OPTION_TYPE_MASK];
271         option[OPT_LEN] = len;
272
273 #if __BYTE_ORDER == __BIG_ENDIAN
274         data <<= 8 * (4 - len);
275 #endif
276
277         dhcp_put_unaligned(data, (uint32_t *) &option[OPT_DATA]);
278         dhcp_add_binary_option(packet, option);
279
280         return;
281 }
282
283 void dhcp_init_header(struct dhcp_packet *packet, char type)
284 {
285         memset(packet, 0, sizeof(*packet));
286
287         packet->op = BOOTREQUEST;
288
289         switch (type) {
290         case DHCPOFFER:
291         case DHCPACK:
292         case DHCPNAK:
293                 packet->op = BOOTREPLY;
294         }
295
296         packet->htype = 1;
297         packet->hlen = 6;
298         packet->cookie = htonl(DHCP_MAGIC);
299         packet->options[0] = DHCP_END;
300
301         dhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type);
302 }
303
304 void dhcpv6_init_header(struct dhcpv6_packet *packet, uint8_t type)
305 {
306         int id;
307
308         memset(packet, 0, sizeof(*packet));
309
310         packet->message = type;
311
312         id = random();
313
314         packet->transaction_id[0] = (id >> 16) & 0xff;
315         packet->transaction_id[1] = (id >> 8) & 0xff;
316         packet->transaction_id[2] = id & 0xff;
317 }
318
319 static gboolean check_vendor(uint8_t  *option_vendor, const char *vendor)
320 {
321         uint8_t vendor_length = sizeof(vendor) - 1;
322
323         if (option_vendor[OPT_LEN - OPT_DATA] != vendor_length)
324                 return FALSE;
325
326         if (memcmp(option_vendor, vendor, vendor_length) != 0)
327                 return FALSE;
328
329         return TRUE;
330 }
331
332 static void check_broken_vendor(struct dhcp_packet *packet)
333 {
334         uint8_t *vendor;
335
336         if (packet->op != BOOTREQUEST)
337                 return;
338
339         vendor = dhcp_get_option(packet, DHCP_VENDOR);
340         if (vendor == NULL)
341                 return;
342
343         if (check_vendor(vendor, "MSFT 98") == TRUE)
344                 packet->flags |= htons(BROADCAST_FLAG);
345 }
346
347 int dhcp_recv_l3_packet(struct dhcp_packet *packet, int fd)
348 {
349         int n;
350
351         memset(packet, 0, sizeof(*packet));
352
353         n = read(fd, packet, sizeof(*packet));
354         if (n < 0)
355                 return -errno;
356
357         if (packet->cookie != htonl(DHCP_MAGIC))
358                 return -EPROTO;
359
360         check_broken_vendor(packet);
361
362         return n;
363 }
364
365 int dhcpv6_recv_l3_packet(struct dhcpv6_packet **packet, unsigned char *buf,
366                         int buf_len, int fd)
367 {
368         int n;
369
370         n = read(fd, buf, buf_len);
371         if (n < 0)
372                 return -errno;
373
374         *packet = (struct dhcpv6_packet *)buf;
375
376         return n;
377 }
378
379 /* TODO: Use glib checksum */
380 uint16_t dhcp_checksum(void *addr, int count)
381 {
382         /*
383          * Compute Internet Checksum for "count" bytes
384          * beginning at location "addr".
385          */
386         int32_t sum = 0;
387         uint16_t *source = (uint16_t *) addr;
388
389         while (count > 1)  {
390                 /*  This is the inner loop */
391                 sum += *source++;
392                 count -= 2;
393         }
394
395         /*  Add left-over byte, if any */
396         if (count > 0) {
397                 /* Make sure that the left-over byte is added correctly both
398                  * with little and big endian hosts */
399                 uint16_t tmp = 0;
400                 *(uint8_t *) &tmp = *(uint8_t *) source;
401                 sum += tmp;
402         }
403         /*  Fold 32-bit sum to 16 bits */
404         while (sum >> 16)
405                 sum = (sum & 0xffff) + (sum >> 16);
406
407         return ~sum;
408 }
409
410 #define IN6ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS_MC_INIT \
411         { { { 0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0x1,0,0x2 } } } /* ff02::1:2 */
412 static const struct in6_addr in6addr_all_dhcp_relay_agents_and_servers_mc =
413         IN6ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS_MC_INIT;
414
415 /* from netinet/in.h */
416 struct in6_pktinfo {
417         struct in6_addr ipi6_addr;  /* src/dst IPv6 address */
418         unsigned int ipi6_ifindex;  /* send/recv interface index */
419 };
420
421 int dhcpv6_send_packet(int index, struct dhcpv6_packet *dhcp_pkt, int len)
422 {
423         struct msghdr m;
424         struct iovec v;
425         struct in6_pktinfo *pktinfo;
426         struct cmsghdr *cmsg;
427         int fd, ret;
428         struct sockaddr_in6 dst;
429         void *control_buf;
430         size_t control_buf_len;
431
432         fd = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
433         if (fd < 0)
434                 return -errno;
435
436         memset(&dst, 0, sizeof(dst));
437         dst.sin6_family = AF_INET6;
438         dst.sin6_port = htons(DHCPV6_SERVER_PORT);
439
440         dst.sin6_addr = in6addr_all_dhcp_relay_agents_and_servers_mc;
441
442         control_buf_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
443         control_buf = g_try_malloc0(control_buf_len);
444         if (control_buf == NULL) {
445                 close(fd);
446                 return -ENOMEM;
447         }
448
449         memset(&m, 0, sizeof(m));
450         memset(&v, 0, sizeof(v));
451
452         m.msg_name = &dst;
453         m.msg_namelen = sizeof(dst);
454
455         v.iov_base = (char *)dhcp_pkt;
456         v.iov_len = len;
457         m.msg_iov = &v;
458         m.msg_iovlen = 1;
459
460         m.msg_control = control_buf;
461         m.msg_controllen = control_buf_len;
462         cmsg = CMSG_FIRSTHDR(&m);
463         cmsg->cmsg_level = IPPROTO_IPV6;
464         cmsg->cmsg_type = IPV6_PKTINFO;
465         cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
466
467         pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
468         memset(pktinfo, 0, sizeof(*pktinfo));
469         pktinfo->ipi6_ifindex = index;
470         m.msg_controllen = cmsg->cmsg_len;
471
472         ret = sendmsg(fd, &m, 0);
473         if (ret < 0)
474                 perror("DHCPv6 msg send failed");
475
476         g_free(control_buf);
477         close(fd);
478
479         return ret;
480 }
481
482 int dhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
483                 uint32_t source_ip, int source_port, uint32_t dest_ip,
484                         int dest_port, const uint8_t *dest_arp, int ifindex)
485 {
486         struct sockaddr_ll dest;
487         struct ip_udp_dhcp_packet packet;
488         int fd, n;
489
490         enum {
491                 IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) -
492                                                 EXTEND_FOR_BUGGY_SERVERS,
493                 UPD_DHCP_SIZE = IP_UPD_DHCP_SIZE -
494                                 offsetof(struct ip_udp_dhcp_packet, udp),
495         };
496
497         fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IP));
498         if (fd < 0)
499                 return -errno;
500
501         memset(&dest, 0, sizeof(dest));
502         memset(&packet, 0, sizeof(packet));
503         packet.data = *dhcp_pkt;
504
505         dest.sll_family = AF_PACKET;
506         dest.sll_protocol = htons(ETH_P_IP);
507         dest.sll_ifindex = ifindex;
508         dest.sll_halen = 6;
509         memcpy(dest.sll_addr, dest_arp, 6);
510         if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
511                 close(fd);
512                 return -errno;
513         }
514
515         packet.ip.protocol = IPPROTO_UDP;
516         packet.ip.saddr = source_ip;
517         packet.ip.daddr = dest_ip;
518         packet.udp.source = htons(source_port);
519         packet.udp.dest = htons(dest_port);
520         /* size, excluding IP header: */
521         packet.udp.len = htons(UPD_DHCP_SIZE);
522         /* for UDP checksumming, ip.len is set to UDP packet len */
523         packet.ip.tot_len = packet.udp.len;
524         packet.udp.check = dhcp_checksum(&packet, IP_UPD_DHCP_SIZE);
525         /* but for sending, it is set to IP packet len */
526         packet.ip.tot_len = htons(IP_UPD_DHCP_SIZE);
527         packet.ip.ihl = sizeof(packet.ip) >> 2;
528         packet.ip.version = IPVERSION;
529         packet.ip.ttl = IPDEFTTL;
530         packet.ip.check = dhcp_checksum(&packet.ip, sizeof(packet.ip));
531
532         /*
533          * Currently we send full-sized DHCP packets (zero padded).
534          * If you need to change this: last byte of the packet is
535          * packet.data.options[dhcp_end_option(packet.data.options)]
536          */
537         n = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0,
538                         (struct sockaddr *) &dest, sizeof(dest));
539         close(fd);
540
541         if (n < 0)
542                 return -errno;
543
544         return n;
545 }
546
547 int dhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
548                                 uint32_t source_ip, int source_port,
549                                 uint32_t dest_ip, int dest_port)
550 {
551         struct sockaddr_in client;
552         int fd, n, opt = 1;
553
554         enum {
555                 DHCP_SIZE = sizeof(struct dhcp_packet) -
556                                         EXTEND_FOR_BUGGY_SERVERS,
557         };
558
559         fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
560         if (fd < 0)
561                 return -errno;
562
563         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
564
565         memset(&client, 0, sizeof(client));
566         client.sin_family = AF_INET;
567         client.sin_port = htons(source_port);
568         client.sin_addr.s_addr = source_ip;
569         if (bind(fd, (struct sockaddr *) &client, sizeof(client)) < 0) {
570                 close(fd);
571                 return -errno;
572         }
573
574         memset(&client, 0, sizeof(client));
575         client.sin_family = AF_INET;
576         client.sin_port = htons(dest_port);
577         client.sin_addr.s_addr = dest_ip;
578         if (connect(fd, (struct sockaddr *) &client, sizeof(client)) < 0) {
579                 close(fd);
580                 return -errno;
581         }
582
583         n = write(fd, dhcp_pkt, DHCP_SIZE);
584
585         close(fd);
586
587         if (n < 0)
588                 return -errno;
589
590         return n;
591 }
592
593 int dhcp_l3_socket(int port, const char *interface, int family)
594 {
595         int fd, opt = 1, len;
596         struct sockaddr_in addr4;
597         struct sockaddr_in6 addr6;
598         struct sockaddr *addr;
599
600         fd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
601         if (fd < 0)
602                 return -errno;
603
604         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
605
606         if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
607                                 interface, strlen(interface) + 1) < 0) {
608                 close(fd);
609                 return -1;
610         }
611
612         if (family == AF_INET) {
613                 memset(&addr4, 0, sizeof(addr4));
614                 addr4.sin_family = family;
615                 addr4.sin_port = htons(port);
616                 addr = (struct sockaddr *)&addr4;
617                 len = sizeof(addr4);
618         } else if (family == AF_INET6) {
619                 memset(&addr6, 0, sizeof(addr6));
620                 addr6.sin6_family = family;
621                 addr6.sin6_port = htons(port);
622                 addr = (struct sockaddr *)&addr6;
623                 len = sizeof(addr6);
624         } else {
625                 close(fd);
626                 return -EINVAL;
627         }
628
629         if (bind(fd, addr, len) != 0) {
630                 close(fd);
631                 return -1;
632         }
633
634         return fd;
635 }
636
637 char *get_interface_name(int index)
638 {
639         struct ifreq ifr;
640         int sk, err;
641
642         if (index < 0)
643                 return NULL;
644
645         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
646         if (sk < 0) {
647                 perror("Open socket error");
648                 return NULL;
649         }
650
651         memset(&ifr, 0, sizeof(ifr));
652         ifr.ifr_ifindex = index;
653
654         err = ioctl(sk, SIOCGIFNAME, &ifr);
655         if (err < 0) {
656                 perror("Get interface name error");
657                 close(sk);
658                 return NULL;
659         }
660
661         close(sk);
662
663         return g_strdup(ifr.ifr_name);
664 }
665
666 gboolean interface_is_up(int index)
667 {
668         int sk, err;
669         struct ifreq ifr;
670         gboolean ret = FALSE;
671
672         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
673         if (sk < 0) {
674                 perror("Open socket error");
675                 return FALSE;
676         }
677
678         memset(&ifr, 0, sizeof(ifr));
679         ifr.ifr_ifindex = index;
680
681         err = ioctl(sk, SIOCGIFNAME, &ifr);
682         if (err < 0) {
683                 perror("Get interface name error");
684                 goto done;
685         }
686
687         err = ioctl(sk, SIOCGIFFLAGS, &ifr);
688         if (err < 0) {
689                 perror("Get interface flags error");
690                 goto done;
691         }
692
693         if (ifr.ifr_flags & IFF_UP)
694                 ret = TRUE;
695
696 done:
697         close(sk);
698
699         return ret;
700 }