gdhcp: Update copyright information
[platform/upstream/connman.git] / gdhcp / common.c
1 /*
2  *  DHCP library with GLib integration
3  *
4  *  Copyright (C) 2007-2012  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                 /* Bad packet */
159                 return NULL;
160
161         while (1) {
162                 opt_code = optionptr[0] << 8 | optionptr[1];
163                 opt_len = len = optionptr[2] << 8 | optionptr[3];
164                 len += 2 + 2; /* skip code and len */
165
166                 rem -= len;
167                 if (rem < 0)
168                         break;
169
170                 if (opt_code == code) {
171                         if (option_len != NULL)
172                                 *option_len = opt_len;
173                         found = optionptr + 2 + 2;
174                         count++;
175                 }
176
177                 if (rem == 0)
178                         break;
179
180                 optionptr += len;
181         }
182
183         if (option_count != NULL)
184                 *option_count = count;
185
186         return found;
187 }
188
189 uint8_t *dhcpv6_get_sub_option(unsigned char *option, uint16_t max_len,
190                         uint16_t *option_code, uint16_t *option_len)
191 {
192         int rem;
193         uint16_t code, len;
194
195         rem = max_len - 2 - 2;
196
197         if (rem <= 0)
198                 /* Bad option */
199                 return NULL;
200
201         code = option[0] << 8 | option[1];
202         len = option[2] << 8 | option[3];
203
204         rem -= len;
205         if (rem < 0)
206                 return NULL;
207
208         *option_code = code;
209         *option_len = len;
210
211         return &option[4];
212 }
213
214 /*
215  * Add an option (supplied in binary form) to the options.
216  * Option format: [code][len][data1][data2]..[dataLEN]
217  */
218 void dhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt)
219 {
220         unsigned len;
221         uint8_t *optionptr = packet->options;
222         unsigned end = dhcp_end_option(optionptr);
223
224         len = OPT_DATA + addopt[OPT_LEN];
225
226         /* end position + (option code/length + addopt length) + end option */
227         if (end + len + 1 >= DHCP_OPTIONS_BUFSIZE)
228                 /* option did not fit into the packet */
229                 return;
230
231         memcpy(optionptr + end, addopt, len);
232
233         optionptr[end + len] = DHCP_END;
234 }
235
236 /*
237  * Add an option (supplied in binary form) to the options.
238  * Option format: [code][len][data1][data2]..[dataLEN]
239  */
240 void dhcpv6_add_binary_option(struct dhcpv6_packet *packet, uint16_t max_len,
241                                 uint16_t *pkt_len, uint8_t *addopt)
242 {
243         unsigned len;
244         uint8_t *optionptr = packet->options;
245
246         len = 2 + 2 + (addopt[2] << 8 | addopt[3]);
247
248         /* end position + (option code/length + addopt length) */
249         if (*pkt_len + len >= max_len)
250                 /* option did not fit into the packet */
251                 return;
252
253         memcpy(optionptr + *pkt_len, addopt, len);
254         *pkt_len += len;
255 }
256
257 void dhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code,
258                                                         uint32_t data)
259 {
260         uint8_t option[6], len;
261         GDHCPOptionType type = dhcp_get_code_type(code);
262
263         if (type == OPTION_UNKNOWN)
264                 return;
265
266         option[OPT_CODE] = code;
267
268         len = dhcp_option_lengths[type & OPTION_TYPE_MASK];
269         option[OPT_LEN] = len;
270
271 #if __BYTE_ORDER == __BIG_ENDIAN
272         data <<= 8 * (4 - len);
273 #endif
274
275         dhcp_put_unaligned(data, (uint32_t *)(option + OPT_DATA));
276         dhcp_add_binary_option(packet, option);
277
278         return;
279 }
280
281 void dhcp_init_header(struct dhcp_packet *packet, char type)
282 {
283         memset(packet, 0, sizeof(*packet));
284
285         packet->op = BOOTREQUEST;
286
287         switch (type) {
288         case DHCPOFFER:
289         case DHCPACK:
290         case DHCPNAK:
291                 packet->op = BOOTREPLY;
292         }
293
294         packet->htype = 1;
295         packet->hlen = 6;
296         packet->cookie = htonl(DHCP_MAGIC);
297         packet->options[0] = DHCP_END;
298
299         dhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type);
300 }
301
302 void dhcpv6_init_header(struct dhcpv6_packet *packet, uint8_t type)
303 {
304         int id;
305
306         memset(packet, 0, sizeof(*packet));
307
308         packet->message = type;
309
310         id = random();
311
312         packet->transaction_id[0] = (id >> 16) & 0xff;
313         packet->transaction_id[1] = (id >> 8) & 0xff;
314         packet->transaction_id[2] = id & 0xff;
315 }
316
317 static gboolean check_vendor(uint8_t  *option_vendor, const char *vendor)
318 {
319         uint8_t vendor_length = sizeof(vendor) - 1;
320
321         if (option_vendor[OPT_LEN - OPT_DATA] != vendor_length)
322                 return FALSE;
323
324         if (memcmp(option_vendor, vendor, vendor_length) != 0)
325                 return FALSE;
326
327         return TRUE;
328 }
329
330 static void check_broken_vendor(struct dhcp_packet *packet)
331 {
332         uint8_t *vendor;
333
334         if (packet->op != BOOTREQUEST)
335                 return;
336
337         vendor = dhcp_get_option(packet, DHCP_VENDOR);
338         if (vendor == NULL)
339                 return;
340
341         if (check_vendor(vendor, "MSFT 98") == TRUE)
342                 packet->flags |= htons(BROADCAST_FLAG);
343 }
344
345 int dhcp_recv_l3_packet(struct dhcp_packet *packet, int fd)
346 {
347         int n;
348
349         memset(packet, 0, sizeof(*packet));
350
351         n = read(fd, packet, sizeof(*packet));
352         if (n < 0)
353                 return -errno;
354
355         if (packet->cookie != htonl(DHCP_MAGIC))
356                 return -EPROTO;
357
358         check_broken_vendor(packet);
359
360         return n;
361 }
362
363 int dhcpv6_recv_l3_packet(struct dhcpv6_packet **packet, unsigned char *buf,
364                         int buf_len, int fd)
365 {
366         int n;
367
368         n = read(fd, buf, buf_len);
369         if (n < 0)
370                 return -errno;
371
372         *packet = (struct dhcpv6_packet *)buf;
373
374         return n;
375 }
376
377 /* TODO: Use glib checksum */
378 uint16_t dhcp_checksum(void *addr, int count)
379 {
380         /*
381          * Compute Internet Checksum for "count" bytes
382          * beginning at location "addr".
383          */
384         int32_t sum = 0;
385         uint16_t *source = (uint16_t *) addr;
386
387         while (count > 1)  {
388                 /*  This is the inner loop */
389                 sum += *source++;
390                 count -= 2;
391         }
392
393         /*  Add left-over byte, if any */
394         if (count > 0) {
395                 /* Make sure that the left-over byte is added correctly both
396                  * with little and big endian hosts */
397                 uint16_t tmp = 0;
398                 *(uint8_t *) &tmp = *(uint8_t *) source;
399                 sum += tmp;
400         }
401         /*  Fold 32-bit sum to 16 bits */
402         while (sum >> 16)
403                 sum = (sum & 0xffff) + (sum >> 16);
404
405         return ~sum;
406 }
407
408 #define IN6ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS_MC_INIT \
409         { { { 0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0x1,0,0x2 } } } /* ff02::1:2 */
410 static const struct in6_addr in6addr_all_dhcp_relay_agents_and_servers_mc =
411         IN6ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS_MC_INIT;
412
413 /* from netinet/in.h */
414 struct in6_pktinfo {
415         struct in6_addr ipi6_addr;  /* src/dst IPv6 address */
416         unsigned int ipi6_ifindex;  /* send/recv interface index */
417 };
418
419 int dhcpv6_send_packet(int index, struct dhcpv6_packet *dhcp_pkt, int len)
420 {
421         struct msghdr m;
422         struct iovec v;
423         struct in6_pktinfo *pktinfo;
424         struct cmsghdr *cmsg;
425         int fd, ret;
426         struct sockaddr_in6 dst;
427         void *control_buf;
428         size_t control_buf_len;
429
430         fd = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
431         if (fd < 0)
432                 return -errno;
433
434         memset(&dst, 0, sizeof(dst));
435         dst.sin6_family = AF_INET6;
436         dst.sin6_port = htons(DHCPV6_SERVER_PORT);
437
438         dst.sin6_addr = in6addr_all_dhcp_relay_agents_and_servers_mc;
439
440         control_buf_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
441         control_buf = g_try_malloc0(control_buf_len);
442         if (control_buf == NULL) {
443                 close(fd);
444                 return -ENOMEM;
445         }
446
447         memset(&m, 0, sizeof(m));
448         memset(&v, 0, sizeof(v));
449
450         m.msg_name = &dst;
451         m.msg_namelen = sizeof(dst);
452
453         v.iov_base = (char *)dhcp_pkt;
454         v.iov_len = len;
455         m.msg_iov = &v;
456         m.msg_iovlen = 1;
457
458         m.msg_control = control_buf;
459         m.msg_controllen = control_buf_len;
460         cmsg = CMSG_FIRSTHDR(&m);
461         cmsg->cmsg_level = IPPROTO_IPV6;
462         cmsg->cmsg_type = IPV6_PKTINFO;
463         cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
464
465         pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
466         memset(pktinfo, 0, sizeof(*pktinfo));
467         pktinfo->ipi6_ifindex = index;
468         m.msg_controllen = cmsg->cmsg_len;
469
470         ret = sendmsg(fd, &m, 0);
471         if (ret < 0)
472                 perror("DHCPv6 msg send failed");
473
474         g_free(control_buf);
475         close(fd);
476
477         return ret;
478 }
479
480 int dhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
481                 uint32_t source_ip, int source_port, uint32_t dest_ip,
482                         int dest_port, const uint8_t *dest_arp, int ifindex)
483 {
484         struct sockaddr_ll dest;
485         struct ip_udp_dhcp_packet packet;
486         int fd, n;
487
488         enum {
489                 IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) -
490                                                 EXTEND_FOR_BUGGY_SERVERS,
491                 UPD_DHCP_SIZE = IP_UPD_DHCP_SIZE -
492                                 offsetof(struct ip_udp_dhcp_packet, udp),
493         };
494
495         fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IP));
496         if (fd < 0)
497                 return -errno;
498
499         memset(&dest, 0, sizeof(dest));
500         memset(&packet, 0, sizeof(packet));
501         packet.data = *dhcp_pkt;
502
503         dest.sll_family = AF_PACKET;
504         dest.sll_protocol = htons(ETH_P_IP);
505         dest.sll_ifindex = ifindex;
506         dest.sll_halen = 6;
507         memcpy(dest.sll_addr, dest_arp, 6);
508         if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
509                 close(fd);
510                 return -errno;
511         }
512
513         packet.ip.protocol = IPPROTO_UDP;
514         packet.ip.saddr = source_ip;
515         packet.ip.daddr = dest_ip;
516         packet.udp.source = htons(source_port);
517         packet.udp.dest = htons(dest_port);
518         /* size, excluding IP header: */
519         packet.udp.len = htons(UPD_DHCP_SIZE);
520         /* for UDP checksumming, ip.len is set to UDP packet len */
521         packet.ip.tot_len = packet.udp.len;
522         packet.udp.check = dhcp_checksum(&packet, IP_UPD_DHCP_SIZE);
523         /* but for sending, it is set to IP packet len */
524         packet.ip.tot_len = htons(IP_UPD_DHCP_SIZE);
525         packet.ip.ihl = sizeof(packet.ip) >> 2;
526         packet.ip.version = IPVERSION;
527         packet.ip.ttl = IPDEFTTL;
528         packet.ip.check = dhcp_checksum(&packet.ip, sizeof(packet.ip));
529
530         /*
531          * Currently we send full-sized DHCP packets (zero padded).
532          * If you need to change this: last byte of the packet is
533          * packet.data.options[dhcp_end_option(packet.data.options)]
534          */
535         n = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0,
536                         (struct sockaddr *) &dest, sizeof(dest));
537         close(fd);
538
539         if (n < 0)
540                 return -errno;
541
542         return n;
543 }
544
545 int dhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
546                                 uint32_t source_ip, int source_port,
547                                 uint32_t dest_ip, int dest_port)
548 {
549         struct sockaddr_in client;
550         int fd, n, opt = 1;
551
552         enum {
553                 DHCP_SIZE = sizeof(struct dhcp_packet) -
554                                         EXTEND_FOR_BUGGY_SERVERS,
555         };
556
557         fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
558         if (fd < 0)
559                 return -errno;
560
561         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
562
563         memset(&client, 0, sizeof(client));
564         client.sin_family = AF_INET;
565         client.sin_port = htons(source_port);
566         client.sin_addr.s_addr = source_ip;
567         if (bind(fd, (struct sockaddr *) &client, sizeof(client)) < 0) {
568                 close(fd);
569                 return -errno;
570         }
571
572         memset(&client, 0, sizeof(client));
573         client.sin_family = AF_INET;
574         client.sin_port = htons(dest_port);
575         client.sin_addr.s_addr = dest_ip;
576         if (connect(fd, (struct sockaddr *) &client, sizeof(client)) < 0) {
577                 close(fd);
578                 return -errno;
579         }
580
581         n = write(fd, dhcp_pkt, DHCP_SIZE);
582
583         close(fd);
584
585         if (n < 0)
586                 return -errno;
587
588         return n;
589 }
590
591 int dhcp_l3_socket(int port, const char *interface, int family)
592 {
593         int fd, opt = 1, len;
594         struct sockaddr_in addr4;
595         struct sockaddr_in6 addr6;
596         struct sockaddr *addr;
597
598         fd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
599         if (fd < 0)
600                 return -errno;
601
602         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
603
604         if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
605                                 interface, strlen(interface) + 1) < 0) {
606                 close(fd);
607                 return -1;
608         }
609
610         if (family == AF_INET) {
611                 memset(&addr4, 0, sizeof(addr4));
612                 addr4.sin_family = family;
613                 addr4.sin_port = htons(port);
614                 addr = (struct sockaddr *)&addr4;
615                 len = sizeof(addr4);
616         } else if (family == AF_INET6) {
617                 memset(&addr6, 0, sizeof(addr6));
618                 addr6.sin6_family = family;
619                 addr6.sin6_port = htons(port);
620                 addr = (struct sockaddr *)&addr6;
621                 len = sizeof(addr6);
622         } else {
623                 close(fd);
624                 return -EINVAL;
625         }
626
627         if (bind(fd, addr, len) != 0) {
628                 close(fd);
629                 return -1;
630         }
631
632         return fd;
633 }
634
635 char *get_interface_name(int index)
636 {
637         struct ifreq ifr;
638         int sk, err;
639
640         if (index < 0)
641                 return NULL;
642
643         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
644         if (sk < 0) {
645                 perror("Open socket error");
646                 return NULL;
647         }
648
649         memset(&ifr, 0, sizeof(ifr));
650         ifr.ifr_ifindex = index;
651
652         err = ioctl(sk, SIOCGIFNAME, &ifr);
653         if (err < 0) {
654                 perror("Get interface name error");
655                 close(sk);
656                 return NULL;
657         }
658
659         close(sk);
660
661         return g_strdup(ifr.ifr_name);
662 }
663
664 gboolean interface_is_up(int index)
665 {
666         int sk, err;
667         struct ifreq ifr;
668         gboolean ret = FALSE;
669
670         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
671         if (sk < 0) {
672                 perror("Open socket error");
673                 return FALSE;
674         }
675
676         memset(&ifr, 0, sizeof(ifr));
677         ifr.ifr_ifindex = index;
678
679         err = ioctl(sk, SIOCGIFNAME, &ifr);
680         if (err < 0) {
681                 perror("Get interface name error");
682                 goto done;
683         }
684
685         err = ioctl(sk, SIOCGIFFLAGS, &ifr);
686         if (err < 0) {
687                 perror("Get interface flags error");
688                 goto done;
689         }
690
691         if (ifr.ifr_flags & IFF_UP)
692                 ret = TRUE;
693
694 done:
695         close(sk);
696
697         return ret;
698 }