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