~ubuntu-branches/ubuntu/oneiric/network-manager/oneiric

« back to all changes in this revision

Viewing changes to src/ip6-manager/nm-ip6-manager.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2010-12-20 13:55:42 UTC
  • mfrom: (1.1.41 upstream)
  • Revision ID: james.westby@ubuntu.com-20101220135542-g89nug62v8lx8kx4
Tags: 0.8.3+git.20101219t181118.e919218-0ubuntu1
* upstream snapshot 2010-12-19 18:11:18 (GMT)
  + e91921814569bf9033fa0779837a77b22eb98e4a 
  - libnm-util: fix a memory leak in nm_setting_to_string()
  - various ipv6 fixes
  - libnm-util: fix nm_utils_security_valid() checks for Ad-Hoc APs
  - dns: direct IPv4 reverse DNS queries to split DNS servers
  - policy: stop touching /etc/hosts
  - dhclient: split out dhclient config merging and add testcases
  - dhclient: explicitly request WPAD option (bgo #368423)
* Drop the patch to not write localhost.localdomain in /etc/hosts, it's no
  longer needed now that NM doesn't change the hosts file.
  - delete debian/patches/never-localhostlocaldomain.patch
  - update debian/patches/series
* debian/libnm-glib2.symbols: Add new symbols for libnm-glib2:
  + nm_dhcp6_config_get_one_option
  + nm_dhcp6_config_get_options
  + nm_dhcp6_config_get_type
  + nm_dhcp6_config_new
* Add vpn-up/vpn-down options for the NM dispatcher script. This should really
  fix bug 661951. (LP: #661951)
  - update debian/network-manager-dispatcher.script

Show diffs side-by-side

added added

removed removed

Lines of Context:
76
76
        time_t expires;
77
77
} NMIP6RDNSS;
78
78
 
 
79
typedef struct {
 
80
        char domain[256];
 
81
        time_t expires;
 
82
} NMIP6DNSSL;
 
83
 
79
84
/******************************************************************/
80
85
 
81
86
typedef struct {
97
102
        GArray *rdnss_servers;
98
103
        guint rdnss_timeout_id;
99
104
 
 
105
        GArray *dnssl_domains;
 
106
        guint dnssl_timeout_id;
 
107
 
100
108
        guint ip6flags_poll_id;
101
109
 
102
110
        guint32 ra_flags;
122
130
                g_array_free (device->rdnss_servers, TRUE);
123
131
        if (device->rdnss_timeout_id)
124
132
                g_source_remove (device->rdnss_timeout_id);
 
133
        if (device->dnssl_domains)
 
134
                g_array_free (device->dnssl_domains, TRUE);
 
135
        if (device->dnssl_timeout_id)
 
136
                g_source_remove (device->dnssl_timeout_id);
125
137
        if (device->ip6flags_poll_id)
126
138
                g_source_remove (device->ip6flags_poll_id);
127
139
 
155
167
 
156
168
        device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
157
169
 
 
170
        device->dnssl_domains = g_array_new (FALSE, FALSE, sizeof (NMIP6DNSSL));
 
171
 
158
172
        g_hash_table_replace (priv->devices, GINT_TO_POINTER (device->ifindex), device);
159
173
 
160
174
        /* and the original value of IPv6 enable/disable */
285
299
                                nm_log_dbg (LOGD_IP6, "(%s): removing expired RA-provided nameserver %s",
286
300
                                            device->iface, buf);
287
301
                        }
288
 
                        g_array_remove_index_fast (device->rdnss_servers, i--);
 
302
                        g_array_remove_index (device->rdnss_servers, i--);
289
303
                        continue;
290
304
                }
291
305
 
300
314
        }
301
315
}
302
316
 
 
317
static void set_dnssl_timeout (NMIP6Device *device);
 
318
 
 
319
static gboolean
 
320
dnssl_expired (gpointer user_data)
 
321
{
 
322
        NMIP6Device *device = user_data;
 
323
        CallbackInfo info = { device, IP6_DHCP_OPT_NONE };
 
324
 
 
325
        nm_log_dbg (LOGD_IP6, "(%s): IPv6 DNSSL information expired", device->iface);
 
326
 
 
327
        set_dnssl_timeout (device);
 
328
        emit_config_changed (&info);
 
329
        return FALSE;
 
330
}
 
331
 
 
332
static void
 
333
set_dnssl_timeout (NMIP6Device *device)
 
334
{
 
335
        time_t expires = 0, now = time (NULL);
 
336
        NMIP6DNSSL *dnssl;
 
337
        int i;
 
338
 
 
339
        if (device->dnssl_timeout_id) {
 
340
                g_source_remove (device->dnssl_timeout_id);
 
341
                device->dnssl_timeout_id = 0;
 
342
        }
 
343
 
 
344
        /* Find the soonest expiration time. */
 
345
        for (i = 0; i < device->dnssl_domains->len; i++) {
 
346
                dnssl = &g_array_index (device->dnssl_domains, NMIP6DNSSL, i);
 
347
                if (dnssl->expires == 0)
 
348
                        continue;
 
349
 
 
350
                /* If the entry has already expired, remove it; the "+ 1" is
 
351
                 * because g_timeout_add_seconds() might fudge the timing a
 
352
                 * bit.
 
353
                 */
 
354
                if (dnssl->expires <= now + 1) {
 
355
                        nm_log_dbg (LOGD_IP6, "(%s): removing expired RA-provided domain %s",
 
356
                                    device->iface, dnssl->domain);
 
357
                        g_array_remove_index (device->dnssl_domains, i--);
 
358
                        continue;
 
359
                }
 
360
 
 
361
                if (!expires || dnssl->expires < expires)
 
362
                        expires = dnssl->expires;
 
363
        }
 
364
 
 
365
        if (expires) {
 
366
                device->dnssl_timeout_id = g_timeout_add_seconds (expires - now,
 
367
                                                                  dnssl_expired,
 
368
                                                                  device);
 
369
        }
 
370
}
 
371
 
303
372
static CallbackInfo *
304
373
callback_info_new (NMIP6Device *device, guint dhcp_opts, gboolean success)
305
374
{
569
638
 */
570
639
 
571
640
#define ND_OPT_RDNSS 25
 
641
#define ND_OPT_DNSSL 31
 
642
 
572
643
struct nd_opt_rdnss {
573
644
        uint8_t nd_opt_rdnss_type;
574
645
        uint8_t nd_opt_rdnss_len;
575
646
        uint16_t nd_opt_rdnss_reserved1;
576
647
        uint32_t nd_opt_rdnss_lifetime;
577
648
        /* followed by one or more IPv6 addresses */
578
 
};
 
649
} __attribute__ ((packed));
 
650
 
 
651
struct nd_opt_dnssl {
 
652
        uint8_t nd_opt_dnssl_type;
 
653
        uint8_t nd_opt_dnssl_len;
 
654
        uint16_t nd_opt_dnssl_reserved1;
 
655
        uint32_t nd_opt_dnssl_lifetime;
 
656
        /* followed by one or more suffixes */
 
657
} __attribute__ ((packed));
 
658
 
 
659
static gboolean
 
660
process_nduseropt_rdnss (NMIP6Device *device, struct nd_opt_hdr *opt)
 
661
{
 
662
        size_t opt_len;
 
663
        struct nd_opt_rdnss *rdnss_opt;
 
664
        time_t now = time (NULL);
 
665
        struct in6_addr *addr;
 
666
        GArray *new_servers;
 
667
        NMIP6RDNSS server, *cur_server;
 
668
        gboolean changed = FALSE;
 
669
        guint i;
 
670
 
 
671
        opt_len = opt->nd_opt_len;
 
672
 
 
673
        if (opt_len < 3 || (opt_len & 1) == 0)
 
674
                return FALSE;
 
675
 
 
676
        rdnss_opt = (struct nd_opt_rdnss *) opt;
 
677
 
 
678
        new_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
 
679
 
 
680
        /* Pad the DNS server expiry somewhat to give a bit of slack in cases
 
681
         * where one RA gets lost or something (which can happen on unreliable
 
682
         * links like WiFi where certain types of frames are not retransmitted).
 
683
         * Note that 0 has special meaning and is therefore not adjusted.
 
684
         */
 
685
        server.expires = ntohl (rdnss_opt->nd_opt_rdnss_lifetime);
 
686
        if (server.expires > 0)
 
687
                server.expires += now + 10;
 
688
 
 
689
        for (addr = (struct in6_addr *) (rdnss_opt + 1); opt_len >= 2; addr++, opt_len -= 2) {
 
690
                char buf[INET6_ADDRSTRLEN + 1];
 
691
 
 
692
                if (!inet_ntop (AF_INET6, addr, buf, sizeof (buf)))
 
693
                        strcpy(buf, "[invalid]");
 
694
 
 
695
                for (i = 0; i < device->rdnss_servers->len; i++) {
 
696
                        cur_server = &(g_array_index (device->rdnss_servers, NMIP6RDNSS, i));
 
697
 
 
698
                        if (!IN6_ARE_ADDR_EQUAL (addr, &cur_server->addr))
 
699
                                continue;
 
700
 
 
701
                        cur_server->expires = server.expires;
 
702
 
 
703
                        if (server.expires > 0) {
 
704
                                nm_log_dbg (LOGD_IP6, "(%s): refreshing RA-provided nameserver %s (expires in %d seconds)",
 
705
                                            device->iface, buf,
 
706
                                            server.expires - now);
 
707
                                break;
 
708
                        }
 
709
 
 
710
                        nm_log_dbg (LOGD_IP6, "(%s): removing RA-provided nameserver %s on router request",
 
711
                                    device->iface, buf);
 
712
 
 
713
                        g_array_remove_index (device->rdnss_servers, i);
 
714
                        changed = TRUE;
 
715
                        break;
 
716
                }
 
717
 
 
718
                if (server.expires == 0)
 
719
                        continue;
 
720
                if (i < device->rdnss_servers->len)
 
721
                        continue;
 
722
 
 
723
                nm_log_dbg (LOGD_IP6, "(%s): found RA-provided nameserver %s (expires in %d seconds)",
 
724
                            device->iface, buf, server.expires - now);
 
725
 
 
726
                server.addr = *addr;
 
727
                g_array_append_val (new_servers, server);
 
728
        }
 
729
 
 
730
        /* New servers must be added in the order they are listed in the
 
731
         * RA option and before any existing servers.
 
732
         *
 
733
         * Note: This is the place to remove servers if we want to cap the
 
734
         *       number of resolvers. The RFC states that the one to expire
 
735
         *       first of the existing servers should be removed.
 
736
         */
 
737
        if (new_servers->len) {
 
738
                g_array_prepend_vals (device->rdnss_servers,
 
739
                                      new_servers->data, new_servers->len);
 
740
                changed = TRUE;
 
741
        }
 
742
 
 
743
        g_array_free (new_servers, TRUE);
 
744
 
 
745
        /* Timeouts may have changed even if IPs didn't */
 
746
        set_rdnss_timeout (device);
 
747
 
 
748
        return changed;
 
749
}
 
750
 
 
751
static const char *
 
752
parse_dnssl_domain (const unsigned char *buffer, size_t maxlen)
 
753
{
 
754
        static char domain[256];
 
755
        size_t label_len;
 
756
 
 
757
        domain[0] = '\0';
 
758
 
 
759
        while (maxlen > 0) {
 
760
                label_len = *buffer;
 
761
                buffer++;
 
762
                maxlen--;
 
763
 
 
764
                if (label_len == 0)
 
765
                        return domain;
 
766
 
 
767
                if (label_len > maxlen)
 
768
                        return NULL;
 
769
                if ((sizeof (domain) - strlen (domain)) < (label_len + 2))
 
770
                        return NULL;
 
771
 
 
772
                if (domain[0] != '\0')
 
773
                        strcat (domain, ".");
 
774
                strncat (domain, (const char *)buffer, label_len);
 
775
                buffer += label_len;
 
776
                maxlen -= label_len;
 
777
        }
 
778
 
 
779
        return NULL;
 
780
}
 
781
 
 
782
static gboolean
 
783
process_nduseropt_dnssl (NMIP6Device *device, struct nd_opt_hdr *opt)
 
784
{
 
785
        size_t opt_len;
 
786
        struct nd_opt_dnssl *dnssl_opt;
 
787
        unsigned char *opt_ptr;
 
788
        time_t now = time (NULL);
 
789
        GArray *new_domains;
 
790
        NMIP6DNSSL domain, *cur_domain;
 
791
        gboolean changed;
 
792
        guint i;
 
793
 
 
794
        opt_len = opt->nd_opt_len;
 
795
 
 
796
        if (opt_len < 2)
 
797
                return FALSE;
 
798
 
 
799
        dnssl_opt = (struct nd_opt_dnssl *) opt;
 
800
 
 
801
        opt_ptr = (unsigned char *)(dnssl_opt + 1);
 
802
        opt_len = (opt_len - 1) * 8; /* prefer bytes for later handling */
 
803
 
 
804
        new_domains = g_array_new (FALSE, FALSE, sizeof (NMIP6DNSSL));
 
805
 
 
806
        changed = FALSE;
 
807
 
 
808
        /* Pad the DNS server expiry somewhat to give a bit of slack in cases
 
809
         * where one RA gets lost or something (which can happen on unreliable
 
810
         * links like wifi where certain types of frames are not retransmitted).
 
811
         * Note that 0 has special meaning and is therefore not adjusted.
 
812
         */
 
813
        domain.expires = ntohl (dnssl_opt->nd_opt_dnssl_lifetime);
 
814
        if (domain.expires > 0)
 
815
                domain.expires += now + 10;
 
816
 
 
817
        while (opt_len) {
 
818
                const char *domain_str;
 
819
 
 
820
                domain_str = parse_dnssl_domain (opt_ptr, opt_len);
 
821
                if (domain_str == NULL) {
 
822
                        nm_log_dbg (LOGD_IP6, "(%s): invalid DNSSL option, parsing aborted",
 
823
                                    device->iface);
 
824
                        break;
 
825
                }
 
826
 
 
827
                /* The DNSSL encoding of domains happen to occupy the same size
 
828
                 * as the length of the resulting string, including terminating
 
829
                 * null. */
 
830
                opt_ptr += strlen (domain_str) + 1;
 
831
                opt_len -= strlen (domain_str) + 1;
 
832
 
 
833
                /* Ignore empty domains. They're probably just padding... */
 
834
                if (domain_str[0] == '\0')
 
835
                        continue;
 
836
 
 
837
                for (i = 0; i < device->dnssl_domains->len; i++) {
 
838
                        cur_domain = &(g_array_index (device->dnssl_domains, NMIP6DNSSL, i));
 
839
 
 
840
                        if (strcmp (domain_str, cur_domain->domain) != 0)
 
841
                                continue;
 
842
 
 
843
                        cur_domain->expires = domain.expires;
 
844
 
 
845
                        if (domain.expires > 0) {
 
846
                                nm_log_dbg (LOGD_IP6, "(%s): refreshing RA-provided domain %s (expires in %d seconds)",
 
847
                                            device->iface, domain_str,
 
848
                                            domain.expires - now);
 
849
                                break;
 
850
                        }
 
851
 
 
852
                        nm_log_dbg (LOGD_IP6, "(%s): removing RA-provided domain %s on router request",
 
853
                                    device->iface, domain_str);
 
854
 
 
855
                        g_array_remove_index (device->dnssl_domains, i);
 
856
                        changed = TRUE;
 
857
                        break;
 
858
                }
 
859
 
 
860
                if (domain.expires == 0)
 
861
                        continue;
 
862
                if (i < device->dnssl_domains->len)
 
863
                        continue;
 
864
 
 
865
                nm_log_dbg (LOGD_IP6, "(%s): found RA-provided domain %s (expires in %d seconds)",
 
866
                            device->iface, domain_str, domain.expires - now);
 
867
 
 
868
                g_assert (strlen (domain_str) < sizeof (domain.domain));
 
869
                strcpy (domain.domain, domain_str);
 
870
                g_array_append_val (new_domains, domain);
 
871
        }
 
872
 
 
873
        /* New domains must be added in the order they are listed in the
 
874
         * RA option and before any existing domains.
 
875
         *
 
876
         * Note: This is the place to remove domains if we want to cap the
 
877
         *       number of domains. The RFC states that the one to expire
 
878
         *       first of the existing domains should be removed.
 
879
         */
 
880
        if (new_domains->len) {
 
881
                g_array_prepend_vals (device->dnssl_domains,
 
882
                                      new_domains->data, new_domains->len);
 
883
                changed = TRUE;
 
884
        }
 
885
 
 
886
        g_array_free (new_domains, TRUE);
 
887
 
 
888
        /* Timeouts may have changed even if domains didn't */
 
889
        set_dnssl_timeout (device);
 
890
 
 
891
        return changed;
 
892
}
579
893
 
580
894
static NMIP6Device *
581
895
process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg)
583
897
        NMIP6Device *device;
584
898
        struct nduseroptmsg *ndmsg;
585
899
        struct nd_opt_hdr *opt;
586
 
        guint opts_len, i;
587
 
        time_t now = time (NULL);
588
 
        struct nd_opt_rdnss *rdnss_opt;
589
 
        struct in6_addr *addr;
590
 
        GArray *servers;
591
 
        NMIP6RDNSS server, *sa, *sb;
592
 
        gboolean changed;
 
900
        guint opts_len;
 
901
        gboolean changed = FALSE;
593
902
 
594
903
        nm_log_dbg (LOGD_IP6, "processing netlink nduseropt message");
595
904
 
608
917
                return NULL;
609
918
        }
610
919
 
611
 
        servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
612
 
 
613
920
        opt = (struct nd_opt_hdr *) (ndmsg + 1);
614
921
        opts_len = ndmsg->nduseropt_opts_len;
615
922
 
619
926
                if (nd_opt_len == 0 || opts_len < (nd_opt_len << 3))
620
927
                        break;
621
928
 
622
 
                if (opt->nd_opt_type != ND_OPT_RDNSS)
623
 
                        goto next;
624
 
 
625
 
                if (nd_opt_len < 3 || (nd_opt_len & 1) == 0)
626
 
                        goto next;
627
 
 
628
 
                rdnss_opt = (struct nd_opt_rdnss *) opt;
629
 
 
630
 
                /* Pad the DNS server expiry somewhat to give a bit of slack in cases
631
 
                 * where one RA gets lost or something (which can happen on unreliable
632
 
                 * links like wifi where certain types of frames are not retransmitted).
633
 
                 */
634
 
                server.expires = now + ntohl (rdnss_opt->nd_opt_rdnss_lifetime) + 10;
635
 
 
636
 
                for (addr = (struct in6_addr *) (rdnss_opt + 1); nd_opt_len >= 2; addr++, nd_opt_len -= 2) {
637
 
                        char buf[INET6_ADDRSTRLEN + 1];
638
 
 
639
 
                        if (inet_ntop (AF_INET6, addr, buf, sizeof (buf))) {
640
 
                                nm_log_dbg (LOGD_IP6, "(%s): found RA-provided nameserver %s (expires in %d seconds)",
641
 
                                            device->iface, buf,
642
 
                                            ntohl (rdnss_opt->nd_opt_rdnss_lifetime));
643
 
                        }
644
 
 
645
 
                        server.addr = *addr;
646
 
                        g_array_append_val (servers, server);
 
929
                switch (opt->nd_opt_type) {
 
930
                case ND_OPT_RDNSS:
 
931
                        changed = process_nduseropt_rdnss (device, opt);
 
932
                        break;
 
933
                case ND_OPT_DNSSL:
 
934
                        changed = process_nduseropt_dnssl (device, opt);
 
935
                        break;
647
936
                }
648
937
 
649
 
        next:
650
938
                opts_len -= opt->nd_opt_len << 3;
651
939
                opt = (struct nd_opt_hdr *) ((uint8_t *) opt + (opt->nd_opt_len << 3));
652
940
        }
653
941
 
654
 
        /* See if anything (other than expiration time) changed */
655
 
        if (servers->len != device->rdnss_servers->len)
656
 
                changed = TRUE;
657
 
        else {
658
 
                for (i = 0; i < servers->len; i++) {
659
 
                        sa = &(g_array_index (servers, NMIP6RDNSS, i));
660
 
                        sb = &(g_array_index (device->rdnss_servers, NMIP6RDNSS, i));
661
 
                        if (IN6_ARE_ADDR_EQUAL (&sa->addr, &sb->addr) == FALSE) {
662
 
                                changed = TRUE;
663
 
                                break;
664
 
                        }
665
 
                }
666
 
                changed = FALSE;
667
 
        }
668
 
 
669
 
        if (changed) {
670
 
                nm_log_dbg (LOGD_IP6, "(%s): RA-provided nameservers changed", device->iface);
671
 
        }
672
 
 
673
 
        /* Always copy in new servers (even if unchanged) to get their updated
674
 
         * expiration times.
675
 
         */
676
 
        g_array_free (device->rdnss_servers, TRUE);
677
 
        device->rdnss_servers = servers;
678
 
 
679
 
        /* Timeouts may have changed even if IPs didn't */
680
 
        set_rdnss_timeout (device);
681
 
 
682
942
        if (changed)
683
943
                return device;
684
944
        else
1014
1274
                        nm_ip6_config_add_nameserver (config, &rdnss[i].addr);
1015
1275
        }
1016
1276
 
 
1277
        /* Add DNS domains */
 
1278
        if (device->dnssl_domains) {
 
1279
                NMIP6DNSSL *dnssl = (NMIP6DNSSL *)(device->dnssl_domains->data);
 
1280
 
 
1281
                for (i = 0; i < device->dnssl_domains->len; i++)
 
1282
                        nm_ip6_config_add_domain (config, dnssl[i].domain);
 
1283
        }
 
1284
 
1017
1285
        return config;
1018
1286
}
1019
1287