2 * DHCP library with GLib integration
4 * Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
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.
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.
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
29 #include <sys/ioctl.h>
33 #include <net/if_arp.h>
35 #include <netpacket/packet.h>
36 #include <net/ethernet.h>
37 #include <arpa/inet.h>
43 static const DHCPOption client_options[] = {
44 { OPTION_IP, 0x01 }, /* subnet-mask */
45 { OPTION_IP | OPTION_LIST, 0x03 }, /* routers */
46 { OPTION_IP | OPTION_LIST, 0x06 }, /* domain-name-servers */
47 { OPTION_STRING, 0x0c }, /* hostname */
48 { OPTION_STRING, 0x0f }, /* domain-name */
49 { OPTION_U16, 0x1a }, /* mtu */
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 },
63 #define URANDOM "/dev/urandom"
64 static int random_fd = -1;
66 int dhcp_get_random(uint64_t *val)
71 random_fd = open(URANDOM, O_RDONLY);
80 if (read(random_fd, val, sizeof(uint64_t)) < 0) {
90 void dhcp_cleanup_random(void)
99 GDHCPOptionType dhcp_get_code_type(uint8_t code)
103 for (i = 0; client_options[i].code; i++) {
104 if (client_options[i].code == code)
105 return client_options[i].type;
108 return OPTION_UNKNOWN;
111 uint8_t *dhcp_get_option(struct dhcp_packet *packet, int code)
115 uint8_t overload = 0;
117 /* option bytes: [code][len][data1][data2]..[dataLEN] */
118 optionptr = packet->options;
119 rem = sizeof(packet->options);
123 /* Bad packet, malformed option field */
126 if (optionptr[OPT_CODE] == DHCP_PADDING) {
133 if (optionptr[OPT_CODE] == DHCP_END) {
134 if (overload & FILE_FIELD) {
135 overload &= ~FILE_FIELD;
137 optionptr = packet->file;
138 rem = sizeof(packet->file);
141 } else if (overload & SNAME_FIELD) {
142 overload &= ~SNAME_FIELD;
144 optionptr = packet->sname;
145 rem = sizeof(packet->sname);
153 len = 2 + optionptr[OPT_LEN];
157 continue; /* complain and return NULL */
159 if (optionptr[OPT_CODE] == code)
160 return optionptr + OPT_DATA;
162 if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD)
163 overload |= optionptr[OPT_DATA];
171 int dhcp_end_option(uint8_t *optionptr)
175 while (optionptr[i] != DHCP_END) {
176 if (optionptr[i] != DHCP_PADDING)
177 i += optionptr[i + OPT_LEN] + OPT_DATA - 1;
185 /* get a rough idea of how long an option will be */
186 static const uint8_t len_of_option_as_string[] = {
187 [OPTION_IP] = sizeof("255.255.255.255 "),
189 [OPTION_U8] = sizeof("255 "),
190 [OPTION_U16] = sizeof("65535 "),
191 [OPTION_U32] = sizeof("4294967295 "),
194 static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
196 return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
199 /* Create "opt_value1 option_value2 ..." string */
200 char *malloc_option_value_string(uint8_t *option, GDHCPOptionType type)
202 unsigned upper_length;
206 len = option[OPT_LEN - OPT_DATA];
207 type &= OPTION_TYPE_MASK;
208 optlen = dhcp_option_lengths[type];
211 upper_length = len_of_option_as_string[type] *
212 ((unsigned)len / (unsigned)optlen);
213 dest = ret = g_malloc(upper_length + 1);
217 while (len >= optlen) {
220 dest += sprint_nip(dest, "", option);
223 uint16_t val_u16 = get_be16(option);
224 dest += sprintf(dest, "%u", val_u16);
228 uint32_t val_u32 = get_be32(option);
229 dest += sprintf(dest, "%u", val_u32);
233 memcpy(dest, option, len);
250 uint8_t *dhcpv6_get_option(struct dhcpv6_packet *packet, uint16_t pkt_len,
251 int code, uint16_t *option_len, int *option_count)
254 uint8_t *optionptr, *found = NULL;
255 uint16_t opt_code, opt_len, len;
257 optionptr = packet->options;
258 rem = pkt_len - 1 - 3;
264 opt_code = optionptr[0] << 8 | optionptr[1];
265 opt_len = len = optionptr[2] << 8 | optionptr[3];
266 len += 2 + 2; /* skip code and len */
275 if (opt_code == code) {
277 *option_len = opt_len;
278 found = optionptr + 2 + 2;
289 *option_count = count;
301 uint8_t *dhcpv6_get_sub_option(unsigned char *option, uint16_t max_len,
302 uint16_t *option_code, uint16_t *option_len)
307 rem = max_len - 2 - 2;
313 code = option[0] << 8 | option[1];
314 len = option[2] << 8 | option[3];
327 * Add an option (supplied in binary form) to the options.
328 * Option format: [code][len][data1][data2]..[dataLEN]
330 void dhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt)
333 uint8_t *optionptr = packet->options;
334 unsigned end = dhcp_end_option(optionptr);
336 len = OPT_DATA + addopt[OPT_LEN];
338 /* end position + (option code/length + addopt length) + end option */
339 if (end + len + 1 >= DHCP_OPTIONS_BUFSIZE)
340 /* option did not fit into the packet */
343 memcpy(optionptr + end, addopt, len);
345 optionptr[end + len] = DHCP_END;
349 * Add an option (supplied in binary form) to the options.
350 * Option format: [code][len][data1][data2]..[dataLEN]
352 void dhcpv6_add_binary_option(struct dhcpv6_packet *packet, uint16_t max_len,
353 uint16_t *pkt_len, uint8_t *addopt)
356 uint8_t *optionptr = packet->options;
358 len = 2 + 2 + (addopt[2] << 8 | addopt[3]);
360 /* end position + (option code/length + addopt length) */
361 if (*pkt_len + len >= max_len)
362 /* option did not fit into the packet */
365 memcpy(optionptr + *pkt_len, addopt, len);
369 static GDHCPOptionType check_option(uint8_t code, uint8_t data_len)
371 GDHCPOptionType type = dhcp_get_code_type(code);
374 if (type == OPTION_UNKNOWN)
377 len = dhcp_option_lengths[type & OPTION_TYPE_MASK];
378 if (len != data_len) {
379 printf("Invalid option len %d (expecting %d) for code 0x%x\n",
380 data_len, len, code);
381 return OPTION_UNKNOWN;
387 void dhcp_add_option_uint32(struct dhcp_packet *packet, uint8_t code,
392 if (check_option(code, sizeof(data)) == OPTION_UNKNOWN)
395 option[OPT_CODE] = code;
396 option[OPT_LEN] = sizeof(data);
397 put_be32(data, option + OPT_DATA);
399 dhcp_add_binary_option(packet, option);
404 void dhcp_add_option_uint16(struct dhcp_packet *packet, uint8_t code,
409 if (check_option(code, sizeof(data)) == OPTION_UNKNOWN)
412 option[OPT_CODE] = code;
413 option[OPT_LEN] = sizeof(data);
414 put_be16(data, option + OPT_DATA);
416 dhcp_add_binary_option(packet, option);
421 void dhcp_add_option_uint8(struct dhcp_packet *packet, uint8_t code,
426 if (check_option(code, sizeof(data)) == OPTION_UNKNOWN)
429 option[OPT_CODE] = code;
430 option[OPT_LEN] = sizeof(data);
431 option[OPT_DATA] = data;
433 dhcp_add_binary_option(packet, option);
438 void dhcp_init_header(struct dhcp_packet *packet, char type)
440 memset(packet, 0, sizeof(*packet));
442 packet->op = BOOTREQUEST;
448 packet->op = BOOTREPLY;
453 packet->cookie = htonl(DHCP_MAGIC);
454 packet->options[0] = DHCP_END;
456 dhcp_add_option_uint8(packet, DHCP_MESSAGE_TYPE, type);
459 void dhcpv6_init_header(struct dhcpv6_packet *packet, uint8_t type)
464 memset(packet, 0, sizeof(*packet));
466 packet->message = type;
468 dhcp_get_random(&rand);
471 packet->transaction_id[0] = (id >> 16) & 0xff;
472 packet->transaction_id[1] = (id >> 8) & 0xff;
473 packet->transaction_id[2] = id & 0xff;
476 int dhcp_recv_l3_packet(struct dhcp_packet *packet, int fd)
480 memset(packet, 0, sizeof(*packet));
482 n = read(fd, packet, sizeof(*packet));
486 if (packet->cookie != htonl(DHCP_MAGIC))
492 int dhcpv6_recv_l3_packet(struct dhcpv6_packet **packet, unsigned char *buf,
497 n = read(fd, buf, buf_len);
501 *packet = (struct dhcpv6_packet *)buf;
506 /* TODO: Use glib checksum */
507 uint16_t dhcp_checksum(void *addr, int count)
510 * Compute Internet Checksum for "count" bytes
511 * beginning at location "addr".
514 uint16_t *source = (uint16_t *) addr;
517 /* This is the inner loop */
522 /* Add left-over byte, if any */
524 /* Make sure that the left-over byte is added correctly both
525 * with little and big endian hosts */
527 *(uint8_t *) &tmp = *(uint8_t *) source;
530 /* Fold 32-bit sum to 16 bits */
532 sum = (sum & 0xffff) + (sum >> 16);
537 #define IN6ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS_MC_INIT \
538 { { { 0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0x1,0,0x2 } } } /* ff02::1:2 */
539 static const struct in6_addr in6addr_all_dhcp_relay_agents_and_servers_mc =
540 IN6ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS_MC_INIT;
542 int dhcpv6_send_packet(int index, struct dhcpv6_packet *dhcp_pkt, int len)
546 struct in6_pktinfo *pktinfo;
547 struct cmsghdr *cmsg;
548 int fd, ret, opt = 1;
549 struct sockaddr_in6 src;
550 struct sockaddr_in6 dst;
552 size_t control_buf_len;
554 fd = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
558 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
564 memset(&src, 0, sizeof(src));
565 src.sin6_family = AF_INET6;
566 src.sin6_port = htons(DHCPV6_CLIENT_PORT);
568 if (bind(fd, (struct sockaddr *) &src, sizeof(src)) <0) {
574 memset(&dst, 0, sizeof(dst));
575 dst.sin6_family = AF_INET6;
576 dst.sin6_port = htons(DHCPV6_SERVER_PORT);
578 dst.sin6_addr = in6addr_all_dhcp_relay_agents_and_servers_mc;
580 control_buf_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
581 control_buf = g_try_malloc0(control_buf_len);
587 memset(&m, 0, sizeof(m));
588 memset(&v, 0, sizeof(v));
591 m.msg_namelen = sizeof(dst);
593 v.iov_base = (char *)dhcp_pkt;
598 m.msg_control = control_buf;
599 m.msg_controllen = control_buf_len;
600 cmsg = CMSG_FIRSTHDR(&m);
601 cmsg->cmsg_level = IPPROTO_IPV6;
602 cmsg->cmsg_type = IPV6_PKTINFO;
603 cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
605 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
606 memset(pktinfo, 0, sizeof(*pktinfo));
607 pktinfo->ipi6_ifindex = index;
608 m.msg_controllen = cmsg->cmsg_len;
610 ret = sendmsg(fd, &m, 0);
612 char *msg = "DHCPv6 msg send failed";
614 if (errno == EADDRNOTAVAIL) {
615 char *str = g_strdup_printf("%s (index %d)",
629 int dhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
630 uint32_t source_ip, int source_port,
631 uint32_t dest_ip, int dest_port,
632 const uint8_t *dest_arp, int ifindex, bool bcast)
634 struct sockaddr_ll dest;
635 struct ip_udp_dhcp_packet packet;
639 IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) -
640 EXTEND_FOR_BUGGY_SERVERS,
641 UPD_DHCP_SIZE = IP_UPD_DHCP_SIZE -
642 offsetof(struct ip_udp_dhcp_packet, udp),
645 fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
650 dhcp_pkt->flags |= htons(BROADCAST_FLAG);
652 memset(&dest, 0, sizeof(dest));
653 memset(&packet, 0, sizeof(packet));
654 packet.data = *dhcp_pkt;
656 dest.sll_family = AF_PACKET;
657 dest.sll_protocol = htons(ETH_P_IP);
658 dest.sll_ifindex = ifindex;
660 memcpy(dest.sll_addr, dest_arp, 6);
661 if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
667 packet.ip.protocol = IPPROTO_UDP;
668 packet.ip.saddr = source_ip;
669 packet.ip.daddr = dest_ip;
670 packet.udp.source = htons(source_port);
671 packet.udp.dest = htons(dest_port);
672 /* size, excluding IP header: */
673 packet.udp.len = htons(UPD_DHCP_SIZE);
674 /* for UDP checksumming, ip.len is set to UDP packet len */
675 packet.ip.tot_len = packet.udp.len;
676 packet.udp.check = dhcp_checksum(&packet, IP_UPD_DHCP_SIZE);
677 /* but for sending, it is set to IP packet len */
678 packet.ip.tot_len = htons(IP_UPD_DHCP_SIZE);
679 packet.ip.ihl = sizeof(packet.ip) >> 2;
680 packet.ip.version = IPVERSION;
681 packet.ip.ttl = IPDEFTTL;
682 packet.ip.check = dhcp_checksum(&packet.ip, sizeof(packet.ip));
685 * Currently we send full-sized DHCP packets (zero padded).
686 * If you need to change this: last byte of the packet is
687 * packet.data.options[dhcp_end_option(packet.data.options)]
689 n = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0,
690 (struct sockaddr *) &dest, sizeof(dest));
702 int dhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
703 uint32_t source_ip, int source_port,
704 uint32_t dest_ip, int dest_port)
706 struct sockaddr_in client;
710 DHCP_SIZE = sizeof(struct dhcp_packet) -
711 EXTEND_FOR_BUGGY_SERVERS,
714 fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
718 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
724 memset(&client, 0, sizeof(client));
725 client.sin_family = AF_INET;
726 client.sin_port = htons(source_port);
727 client.sin_addr.s_addr = htonl(source_ip);
728 if (bind(fd, (struct sockaddr *) &client, sizeof(client)) < 0) {
734 memset(&client, 0, sizeof(client));
735 client.sin_family = AF_INET;
736 client.sin_port = htons(dest_port);
737 client.sin_addr.s_addr = htonl(dest_ip);
738 if (connect(fd, (struct sockaddr *) &client, sizeof(client)) < 0) {
744 n = write(fd, dhcp_pkt, DHCP_SIZE);
756 int dhcp_l3_socket(int port, const char *interface, int family)
758 int fd, opt = 1, len;
759 struct sockaddr_in addr4;
760 struct sockaddr_in6 addr6;
761 struct sockaddr *addr;
763 fd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
767 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
773 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
774 interface, strlen(interface) + 1) < 0) {
780 if (family == AF_INET) {
781 memset(&addr4, 0, sizeof(addr4));
782 addr4.sin_family = family;
783 addr4.sin_port = htons(port);
784 addr = (struct sockaddr *)&addr4;
786 } else if (family == AF_INET6) {
787 memset(&addr6, 0, sizeof(addr6));
788 addr6.sin6_family = family;
789 addr6.sin6_port = htons(port);
790 addr = (struct sockaddr *)&addr6;
797 if (bind(fd, addr, len) != 0) {
805 char *get_interface_name(int index)
813 sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
815 perror("Open socket error");
819 memset(&ifr, 0, sizeof(ifr));
820 ifr.ifr_ifindex = index;
822 err = ioctl(sk, SIOCGIFNAME, &ifr);
824 perror("Get interface name error");
831 return g_strdup(ifr.ifr_name);
834 bool interface_is_up(int index)
840 sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
842 perror("Open socket error");
846 memset(&ifr, 0, sizeof(ifr));
847 ifr.ifr_ifindex = index;
849 err = ioctl(sk, SIOCGIFNAME, &ifr);
851 perror("Get interface name error");
855 err = ioctl(sk, SIOCGIFFLAGS, &ifr);
857 perror("Get interface flags error");
861 if (ifr.ifr_flags & IFF_UP)