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