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