Updated connman to version 1.35
[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 #include <fcntl.h>
39
40 #include "gdhcp.h"
41 #include "common.h"
42
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 },
61 };
62
63 #define URANDOM "/dev/urandom"
64 static int random_fd = -1;
65
66 int dhcp_get_random(uint64_t *val)
67 {
68         int r;
69
70         if (random_fd < 0) {
71                 random_fd = open(URANDOM, O_RDONLY);
72                 if (random_fd < 0) {
73                         r = -errno;
74                         *val = random();
75
76                         return r;
77                 }
78         }
79
80         if (read(random_fd, val, sizeof(uint64_t)) < 0) {
81                 r = -errno;
82                 *val = random();
83
84                 return r;
85         }
86
87         return 0;
88 }
89
90 void dhcp_cleanup_random(void)
91 {
92         if (random_fd < 0)
93                 return;
94
95         close(random_fd);
96         random_fd = -1;
97 }
98
99 GDHCPOptionType dhcp_get_code_type(uint8_t code)
100 {
101         int i;
102
103         for (i = 0; client_options[i].code; i++) {
104                 if (client_options[i].code == code)
105                         return client_options[i].type;
106         }
107
108         return OPTION_UNKNOWN;
109 }
110
111 uint8_t *dhcp_get_option(struct dhcp_packet *packet, int code)
112 {
113         int len, rem;
114         uint8_t *optionptr;
115         uint8_t overload = 0;
116
117         /* option bytes: [code][len][data1][data2]..[dataLEN] */
118         optionptr = packet->options;
119         rem = sizeof(packet->options);
120
121         while (1) {
122                 if (rem <= 0)
123                         /* Bad packet, malformed option field */
124                         return NULL;
125
126                 if (optionptr[OPT_CODE] == DHCP_PADDING) {
127                         rem--;
128                         optionptr++;
129
130                         continue;
131                 }
132
133                 if (optionptr[OPT_CODE] == DHCP_END) {
134                         if (overload & FILE_FIELD) {
135                                 overload &= ~FILE_FIELD;
136
137                                 optionptr = packet->file;
138                                 rem = sizeof(packet->file);
139
140                                 continue;
141                         } else if (overload & SNAME_FIELD) {
142                                 overload &= ~SNAME_FIELD;
143
144                                 optionptr = packet->sname;
145                                 rem = sizeof(packet->sname);
146
147                                 continue;
148                         }
149
150                         break;
151                 }
152
153                 len = 2 + optionptr[OPT_LEN];
154
155                 rem -= len;
156                 if (rem < 0)
157                         continue; /* complain and return NULL */
158
159                 if (optionptr[OPT_CODE] == code)
160                         return optionptr + OPT_DATA;
161
162                 if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD)
163                         overload |= optionptr[OPT_DATA];
164
165                 optionptr += len;
166         }
167
168         return NULL;
169 }
170
171 int dhcp_end_option(uint8_t *optionptr)
172 {
173         int i = 0;
174
175         while (optionptr[i] != DHCP_END) {
176                 if (optionptr[i] != DHCP_PADDING)
177                         i += optionptr[i + OPT_LEN] + OPT_DATA - 1;
178
179                 i++;
180         }
181
182         return i;
183 }
184
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 "),
188         [OPTION_STRING] = 1,
189         [OPTION_U8] = sizeof("255 "),
190         [OPTION_U16] = sizeof("65535 "),
191         [OPTION_U32] = sizeof("4294967295 "),
192 };
193
194 static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
195 {
196         return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
197 }
198
199 /* Create "opt_value1 option_value2 ..." string */
200 char *malloc_option_value_string(uint8_t *option, GDHCPOptionType type)
201 {
202         unsigned upper_length;
203         int len, optlen;
204         char *dest, *ret;
205
206         len = option[OPT_LEN - OPT_DATA];
207         type &= OPTION_TYPE_MASK;
208         optlen = dhcp_option_lengths[type];
209         if (optlen == 0)
210                 return NULL;
211         upper_length = len_of_option_as_string[type] *
212                         ((unsigned)len / (unsigned)optlen);
213         dest = ret = g_malloc(upper_length + 1);
214         if (ret == NULL)
215                 return NULL;
216
217         while (len >= optlen) {
218                 switch (type) {
219                 case OPTION_IP:
220                         dest += sprint_nip(dest, "", option);
221                         break;
222                 case OPTION_U16: {
223                         uint16_t val_u16 = get_be16(option);
224                         dest += sprintf(dest, "%u", val_u16);
225                         break;
226                 }
227                 case OPTION_U32: {
228                         uint32_t val_u32 = get_be32(option);
229                         dest += sprintf(dest, "%u", val_u32);
230                         break;
231                 }
232                 case OPTION_STRING:
233                         memcpy(dest, option, len);
234                         dest[len] = '\0';
235                         return ret;
236                 default:
237                         break;
238                 }
239                 option += optlen;
240                 len -= optlen;
241                 if (len <= 0)
242                         break;
243                 *dest++ = ' ';
244                 *dest = '\0';
245         }
246
247         return ret;
248 }
249
250 uint8_t *dhcpv6_get_option(struct dhcpv6_packet *packet, uint16_t pkt_len,
251                         int code, uint16_t *option_len, int *option_count)
252 {
253         int rem, count = 0;
254         uint8_t *optionptr, *found = NULL;
255         uint16_t opt_code, opt_len, len;
256
257         optionptr = packet->options;
258         rem = pkt_len - 1 - 3;
259
260         if (rem <= 0)
261                 goto bad_packet;
262
263         while (1) {
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 */
267
268                 if (len < 4)
269                         goto bad_packet;
270
271                 rem -= len;
272                 if (rem < 0)
273                         break;
274
275                 if (opt_code == code) {
276                         if (option_len)
277                                 *option_len = opt_len;
278                         found = optionptr + 2 + 2;
279                         count++;
280                 }
281
282                 if (rem == 0)
283                         break;
284
285                 optionptr += len;
286         }
287
288         if (option_count)
289                 *option_count = count;
290
291         return found;
292
293 bad_packet:
294         if (option_len)
295                 *option_len = 0;
296         if (option_count)
297                 *option_count = 0;
298         return NULL;
299 }
300
301 uint8_t *dhcpv6_get_sub_option(unsigned char *option, uint16_t max_len,
302                         uint16_t *option_code, uint16_t *option_len)
303 {
304         int rem;
305         uint16_t code, len;
306
307         rem = max_len - 2 - 2;
308
309         if (rem <= 0)
310                 /* Bad option */
311                 return NULL;
312
313         code = option[0] << 8 | option[1];
314         len = option[2] << 8 | option[3];
315
316         rem -= len;
317         if (rem < 0)
318                 return NULL;
319
320         *option_code = code;
321         *option_len = len;
322
323         return &option[4];
324 }
325
326 /*
327  * Add an option (supplied in binary form) to the options.
328  * Option format: [code][len][data1][data2]..[dataLEN]
329  */
330 void dhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt)
331 {
332         unsigned len;
333         uint8_t *optionptr = packet->options;
334         unsigned end = dhcp_end_option(optionptr);
335
336         len = OPT_DATA + addopt[OPT_LEN];
337
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 */
341                 return;
342
343         memcpy(optionptr + end, addopt, len);
344
345         optionptr[end + len] = DHCP_END;
346 }
347
348 /*
349  * Add an option (supplied in binary form) to the options.
350  * Option format: [code][len][data1][data2]..[dataLEN]
351  */
352 void dhcpv6_add_binary_option(struct dhcpv6_packet *packet, uint16_t max_len,
353                                 uint16_t *pkt_len, uint8_t *addopt)
354 {
355         unsigned len;
356         uint8_t *optionptr = packet->options;
357
358         len = 2 + 2 + (addopt[2] << 8 | addopt[3]);
359
360         /* end position + (option code/length + addopt length) */
361         if (*pkt_len + len >= max_len)
362                 /* option did not fit into the packet */
363                 return;
364
365         memcpy(optionptr + *pkt_len, addopt, len);
366         *pkt_len += len;
367 }
368
369 static GDHCPOptionType check_option(uint8_t code, uint8_t data_len)
370 {
371         GDHCPOptionType type = dhcp_get_code_type(code);
372         uint8_t len;
373
374         if (type == OPTION_UNKNOWN)
375                 return type;
376
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;
382         }
383
384         return type;
385 }
386
387 void dhcp_add_option_uint32(struct dhcp_packet *packet, uint8_t code,
388                                                         uint32_t data)
389 {
390         uint8_t option[6];
391
392         if (check_option(code, sizeof(data)) == OPTION_UNKNOWN)
393                 return;
394
395         option[OPT_CODE] = code;
396         option[OPT_LEN] = sizeof(data);
397         put_be32(data, option + OPT_DATA);
398
399         dhcp_add_binary_option(packet, option);
400
401         return;
402 }
403
404 void dhcp_add_option_uint16(struct dhcp_packet *packet, uint8_t code,
405                                                         uint16_t data)
406 {
407         uint8_t option[6];
408
409         if (check_option(code, sizeof(data)) == OPTION_UNKNOWN)
410                 return;
411
412         option[OPT_CODE] = code;
413         option[OPT_LEN] = sizeof(data);
414         put_be16(data, option + OPT_DATA);
415
416         dhcp_add_binary_option(packet, option);
417
418         return;
419 }
420
421 void dhcp_add_option_uint8(struct dhcp_packet *packet, uint8_t code,
422                                                         uint8_t data)
423 {
424         uint8_t option[6];
425
426         if (check_option(code, sizeof(data)) == OPTION_UNKNOWN)
427                 return;
428
429         option[OPT_CODE] = code;
430         option[OPT_LEN] = sizeof(data);
431         option[OPT_DATA] = data;
432
433         dhcp_add_binary_option(packet, option);
434
435         return;
436 }
437
438 void dhcp_init_header(struct dhcp_packet *packet, char type)
439 {
440         memset(packet, 0, sizeof(*packet));
441
442         packet->op = BOOTREQUEST;
443
444         switch (type) {
445         case DHCPOFFER:
446         case DHCPACK:
447         case DHCPNAK:
448                 packet->op = BOOTREPLY;
449         }
450
451         packet->htype = 1;
452         packet->hlen = 6;
453         packet->cookie = htonl(DHCP_MAGIC);
454         packet->options[0] = DHCP_END;
455
456         dhcp_add_option_uint8(packet, DHCP_MESSAGE_TYPE, type);
457 }
458
459 void dhcpv6_init_header(struct dhcpv6_packet *packet, uint8_t type)
460 {
461         int id;
462         uint64_t rand;
463
464         memset(packet, 0, sizeof(*packet));
465
466         packet->message = type;
467
468         dhcp_get_random(&rand);
469         id = rand;
470
471         packet->transaction_id[0] = (id >> 16) & 0xff;
472         packet->transaction_id[1] = (id >> 8) & 0xff;
473         packet->transaction_id[2] = id & 0xff;
474 }
475
476 int dhcp_recv_l3_packet(struct dhcp_packet *packet, int fd)
477 {
478         int n;
479
480         memset(packet, 0, sizeof(*packet));
481
482         n = read(fd, packet, sizeof(*packet));
483         if (n < 0)
484                 return -errno;
485
486         if (packet->cookie != htonl(DHCP_MAGIC))
487                 return -EPROTO;
488
489         return n;
490 }
491
492 int dhcpv6_recv_l3_packet(struct dhcpv6_packet **packet, unsigned char *buf,
493                         int buf_len, int fd)
494 {
495         int n;
496
497         n = read(fd, buf, buf_len);
498         if (n < 0)
499                 return -errno;
500
501         *packet = (struct dhcpv6_packet *)buf;
502
503         return n;
504 }
505
506 /* TODO: Use glib checksum */
507 uint16_t dhcp_checksum(void *addr, int count)
508 {
509         /*
510          * Compute Internet Checksum for "count" bytes
511          * beginning at location "addr".
512          */
513         int32_t sum = 0;
514         uint16_t *source = (uint16_t *) addr;
515
516         while (count > 1)  {
517                 /*  This is the inner loop */
518                 sum += *source++;
519                 count -= 2;
520         }
521
522         /*  Add left-over byte, if any */
523         if (count > 0) {
524                 /* Make sure that the left-over byte is added correctly both
525                  * with little and big endian hosts */
526                 uint16_t tmp = 0;
527                 *(uint8_t *) &tmp = *(uint8_t *) source;
528                 sum += tmp;
529         }
530         /*  Fold 32-bit sum to 16 bits */
531         while (sum >> 16)
532                 sum = (sum & 0xffff) + (sum >> 16);
533
534         return ~sum;
535 }
536
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;
541
542 int dhcpv6_send_packet(int index, struct dhcpv6_packet *dhcp_pkt, int len)
543 {
544         struct msghdr m;
545         struct iovec v;
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;
551         void *control_buf;
552         size_t control_buf_len;
553
554         fd = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
555         if (fd < 0)
556                 return -errno;
557
558         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
559                 int err = errno;
560                 close(fd);
561                 return -err;
562         }
563
564         memset(&src, 0, sizeof(src));
565         src.sin6_family = AF_INET6;
566         src.sin6_port = htons(DHCPV6_CLIENT_PORT);
567
568         if (bind(fd, (struct sockaddr *) &src, sizeof(src)) <0) {
569                 int err = errno;
570                 close(fd);
571                 return -err;
572         }
573
574         memset(&dst, 0, sizeof(dst));
575         dst.sin6_family = AF_INET6;
576         dst.sin6_port = htons(DHCPV6_SERVER_PORT);
577
578         dst.sin6_addr = in6addr_all_dhcp_relay_agents_and_servers_mc;
579
580         control_buf_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
581         control_buf = g_try_malloc0(control_buf_len);
582         if (!control_buf) {
583                 close(fd);
584                 return -ENOMEM;
585         }
586
587         memset(&m, 0, sizeof(m));
588         memset(&v, 0, sizeof(v));
589
590         m.msg_name = &dst;
591         m.msg_namelen = sizeof(dst);
592
593         v.iov_base = (char *)dhcp_pkt;
594         v.iov_len = len;
595         m.msg_iov = &v;
596         m.msg_iovlen = 1;
597
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));
604
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;
609
610         ret = sendmsg(fd, &m, 0);
611         if (ret < 0) {
612                 char *msg = "DHCPv6 msg send failed";
613
614                 if (errno == EADDRNOTAVAIL) {
615                         char *str = g_strdup_printf("%s (index %d)",
616                                         msg, index);
617                         perror(str);
618                         g_free(str);
619                 } else
620                         perror(msg);
621         }
622
623         g_free(control_buf);
624         close(fd);
625
626         return ret;
627 }
628
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)
633 {
634         struct sockaddr_ll dest;
635         struct ip_udp_dhcp_packet packet;
636         int fd, n;
637
638         enum {
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),
643         };
644
645         fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
646         if (fd < 0)
647                 return -errno;
648
649         if (bcast)
650                 dhcp_pkt->flags |= htons(BROADCAST_FLAG);
651
652         memset(&dest, 0, sizeof(dest));
653         memset(&packet, 0, sizeof(packet));
654         packet.data = *dhcp_pkt;
655
656         dest.sll_family = AF_PACKET;
657         dest.sll_protocol = htons(ETH_P_IP);
658         dest.sll_ifindex = ifindex;
659         dest.sll_halen = 6;
660         memcpy(dest.sll_addr, dest_arp, 6);
661         if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
662                 int err = errno;
663                 close(fd);
664                 return -err;
665         }
666
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));
683
684         /*
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)]
688          */
689         n = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0,
690                         (struct sockaddr *) &dest, sizeof(dest));
691         if (n < 0) {
692                 int err = errno;
693                 close(fd);
694                 return -err;
695         }
696
697         close(fd);
698
699         return n;
700 }
701
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)
705 {
706         struct sockaddr_in client;
707         int fd, n, opt = 1;
708
709         enum {
710                 DHCP_SIZE = sizeof(struct dhcp_packet) -
711                                         EXTEND_FOR_BUGGY_SERVERS,
712         };
713
714         fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
715         if (fd < 0)
716                 return -errno;
717
718         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
719                 int err = errno;
720                 close(fd);
721                 return -err;
722         }
723
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) {
729                 int err = errno;
730                 close(fd);
731                 return -err;
732         }
733
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) {
739                 int err = errno;
740                 close(fd);
741                 return -err;
742         }
743
744         n = write(fd, dhcp_pkt, DHCP_SIZE);
745         if (n < 0) {
746                 int err = errno;
747                 close(fd);
748                 return -err;
749         }
750
751         close(fd);
752
753         return n;
754 }
755
756 int dhcp_l3_socket(int port, const char *interface, int family)
757 {
758         int fd, opt = 1, len;
759         struct sockaddr_in addr4;
760         struct sockaddr_in6 addr6;
761         struct sockaddr *addr;
762
763         fd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
764         if (fd < 0)
765                 return -errno;
766
767         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
768                 int err = errno;
769                 close(fd);
770                 return -err;
771         }
772
773         if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
774                                 interface, strlen(interface) + 1) < 0) {
775                 int err = errno;
776                 close(fd);
777                 return -err;
778         }
779
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;
785                 len = sizeof(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;
791                 len = sizeof(addr6);
792         } else {
793                 close(fd);
794                 return -EINVAL;
795         }
796
797         if (bind(fd, addr, len) != 0) {
798                 close(fd);
799                 return -1;
800         }
801
802         return fd;
803 }
804
805 char *get_interface_name(int index)
806 {
807         struct ifreq ifr;
808         int sk, err;
809
810         if (index < 0)
811                 return NULL;
812
813         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
814         if (sk < 0) {
815                 perror("Open socket error");
816                 return NULL;
817         }
818
819         memset(&ifr, 0, sizeof(ifr));
820         ifr.ifr_ifindex = index;
821
822         err = ioctl(sk, SIOCGIFNAME, &ifr);
823         if (err < 0) {
824                 perror("Get interface name error");
825                 close(sk);
826                 return NULL;
827         }
828
829         close(sk);
830
831         return g_strdup(ifr.ifr_name);
832 }
833
834 bool interface_is_up(int index)
835 {
836         int sk, err;
837         struct ifreq ifr;
838         bool ret = false;
839
840         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
841         if (sk < 0) {
842                 perror("Open socket error");
843                 return false;
844         }
845
846         memset(&ifr, 0, sizeof(ifr));
847         ifr.ifr_ifindex = index;
848
849         err = ioctl(sk, SIOCGIFNAME, &ifr);
850         if (err < 0) {
851                 perror("Get interface name error");
852                 goto done;
853         }
854
855         err = ioctl(sk, SIOCGIFFLAGS, &ifr);
856         if (err < 0) {
857                 perror("Get interface flags error");
858                 goto done;
859         }
860
861         if (ifr.ifr_flags & IFF_UP)
862                 ret = true;
863
864 done:
865         close(sk);
866
867         return ret;
868 }