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