~ubuntu-branches/ubuntu/trusty/systemd/trusty

« back to all changes in this revision

Viewing changes to src/nss-myhostname/netlink.c

Tags: upstream-202
ImportĀ upstreamĀ versionĀ 202

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
 
37
37
#include "ifconf.h"
38
38
 
 
39
#define SEQ 4711
 
40
 
 
41
static int read_reply(int fd, struct address **list, unsigned *n_list) {
 
42
        ssize_t bytes;
 
43
        struct cmsghdr *cmsg;
 
44
        struct ucred *ucred;
 
45
        struct nlmsghdr *p;
 
46
        uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
 
47
        struct {
 
48
                struct nlmsghdr hdr;
 
49
                struct ifaddrmsg ifaddrmsg;
 
50
                uint8_t payload[16*1024];
 
51
        } resp;
 
52
        struct iovec iov = {
 
53
                .iov_base = &resp,
 
54
                .iov_len = sizeof(resp),
 
55
        };
 
56
        struct msghdr msg = {
 
57
                .msg_name = NULL,
 
58
                .msg_namelen = 0,
 
59
                .msg_iov = &iov,
 
60
                .msg_iovlen = 1,
 
61
                .msg_control = cred_buffer,
 
62
                .msg_controllen = sizeof(cred_buffer),
 
63
                .msg_flags = 0,
 
64
        };
 
65
 
 
66
        assert(fd >= 0);
 
67
        assert(list);
 
68
 
 
69
        bytes = recvmsg(fd, &msg, 0);
 
70
        if (bytes < 0)
 
71
                return -errno;
 
72
 
 
73
        cmsg = CMSG_FIRSTHDR(&msg);
 
74
        if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
 
75
                return -EIO;
 
76
 
 
77
        ucred = (struct ucred*) CMSG_DATA(cmsg);
 
78
        if (ucred->uid != 0 || ucred->pid != 0)
 
79
                return 0;
 
80
 
 
81
        for (p = &resp.hdr; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
 
82
                struct ifaddrmsg *ifaddrmsg;
 
83
                struct rtattr *a;
 
84
                size_t l;
 
85
                void *local = NULL, *address = NULL;
 
86
 
 
87
                if (!NLMSG_OK(p, (size_t) bytes))
 
88
                        return -EIO;
 
89
 
 
90
                if (p->nlmsg_seq != SEQ)
 
91
                        continue;
 
92
 
 
93
                if (p->nlmsg_type == NLMSG_DONE)
 
94
                        return 1;
 
95
 
 
96
                if (p->nlmsg_type == NLMSG_ERROR) {
 
97
                        struct nlmsgerr *nlmsgerr;
 
98
 
 
99
                        nlmsgerr = NLMSG_DATA(p);
 
100
                        return -nlmsgerr->error;
 
101
                }
 
102
 
 
103
                if (p->nlmsg_type != RTM_NEWADDR)
 
104
                        continue;
 
105
 
 
106
                ifaddrmsg = NLMSG_DATA(p);
 
107
 
 
108
                if (ifaddrmsg->ifa_family != AF_INET &&
 
109
                    ifaddrmsg->ifa_family != AF_INET6)
 
110
                        continue;
 
111
 
 
112
                if (ifaddrmsg->ifa_scope == RT_SCOPE_HOST ||
 
113
                    ifaddrmsg->ifa_scope == RT_SCOPE_NOWHERE)
 
114
                        continue;
 
115
 
 
116
                if (ifaddrmsg->ifa_flags & IFA_F_DEPRECATED)
 
117
                        continue;
 
118
 
 
119
                l = NLMSG_PAYLOAD(p, sizeof(struct ifaddrmsg));
 
120
                a = IFA_RTA(ifaddrmsg);
 
121
 
 
122
                while (RTA_OK(a, l)) {
 
123
 
 
124
                        if (a->rta_type == IFA_ADDRESS)
 
125
                                address = RTA_DATA(a);
 
126
                        else if (a->rta_type == IFA_LOCAL)
 
127
                                local = RTA_DATA(a);
 
128
 
 
129
                        a = RTA_NEXT(a, l);
 
130
                }
 
131
 
 
132
                if (local)
 
133
                        address = local;
 
134
 
 
135
                if (!address)
 
136
                        continue;
 
137
 
 
138
                *list = realloc(*list, (*n_list+1) * sizeof(struct address));
 
139
                if (!*list)
 
140
                        return -ENOMEM;
 
141
 
 
142
                (*list)[*n_list].family = ifaddrmsg->ifa_family;
 
143
                (*list)[*n_list].scope = ifaddrmsg->ifa_scope;
 
144
                memcpy((*list)[*n_list].address,
 
145
                       address, ifaddrmsg->ifa_family == AF_INET ? 4 : 16);
 
146
                (*list)[*n_list].ifindex = ifaddrmsg->ifa_index;
 
147
 
 
148
                (*n_list)++;
 
149
        }
 
150
 
 
151
        return 0;
 
152
}
 
153
 
 
154
 
39
155
int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
40
156
 
41
157
        struct {
42
158
                struct nlmsghdr hdr;
43
159
                struct rtgenmsg gen;
44
 
        } req;
45
 
        struct rtgenmsg *gen;
46
 
        int fd, r, on = 1;
47
 
        uint32_t seq = 4711;
 
160
        } req = { {
 
161
                        .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
 
162
                        .nlmsg_type = RTM_GETADDR,
 
163
                        .nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ACK,
 
164
                        .nlmsg_seq = SEQ,
 
165
                        .nlmsg_pid = 0,
 
166
                }, {
 
167
                        .rtgen_family = AF_UNSPEC,
 
168
                }
 
169
        };
 
170
        int r, on = 1;
48
171
        struct address *list = NULL;
49
172
        unsigned n_list = 0;
 
173
        int fd;
50
174
 
51
175
        fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
52
176
        if (fd < 0)
57
181
                goto finish;
58
182
        }
59
183
 
60
 
        memset(&req, 0, sizeof(req));
61
 
        req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
62
 
        req.hdr.nlmsg_type = RTM_GETADDR;
63
 
        req.hdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ACK;
64
 
        req.hdr.nlmsg_seq = seq;
65
 
        req.hdr.nlmsg_pid = 0;
66
 
 
67
 
        gen = NLMSG_DATA(&req.hdr);
68
 
        gen->rtgen_family = AF_UNSPEC;
69
 
 
70
184
        if (send(fd, &req, req.hdr.nlmsg_len, 0) < 0) {
71
185
                r = -errno;
72
186
                goto finish;
73
187
        }
74
188
 
75
 
        for (;;) {
76
 
                ssize_t bytes;
77
 
                struct msghdr msg;
78
 
                struct cmsghdr *cmsg;
79
 
                struct ucred *ucred;
80
 
                struct iovec iov;
81
 
                struct nlmsghdr *p;
82
 
                uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
83
 
                struct {
84
 
                        struct nlmsghdr hdr;
85
 
                        struct ifaddrmsg ifaddrmsg;
86
 
                        uint8_t payload[16*1024];
87
 
                } resp;
88
 
 
89
 
                memset(&iov, 0, sizeof(iov));
90
 
                iov.iov_base = &resp;
91
 
                iov.iov_len = sizeof(resp);
92
 
 
93
 
                memset(&msg, 0, sizeof(msg));
94
 
                msg.msg_name = NULL;
95
 
                msg.msg_namelen = 0;
96
 
                msg.msg_iov = &iov;
97
 
                msg.msg_iovlen = 1;
98
 
                msg.msg_control = cred_buffer;
99
 
                msg.msg_controllen = sizeof(cred_buffer);
100
 
                msg.msg_flags = 0;
101
 
 
102
 
                bytes = recvmsg(fd, &msg, 0);
103
 
                if (bytes < 0) {
104
 
                        r = -errno;
105
 
                        goto finish;
106
 
                }
107
 
 
108
 
                cmsg = CMSG_FIRSTHDR(&msg);
109
 
                if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) {
110
 
                        r = -EIO;
111
 
                        goto finish;
112
 
                }
113
 
 
114
 
                ucred = (struct ucred*) CMSG_DATA(cmsg);
115
 
                if (ucred->uid != 0 || ucred->pid != 0)
116
 
                        continue;
117
 
 
118
 
                for (p = &resp.hdr; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
119
 
                        struct ifaddrmsg *ifaddrmsg;
120
 
                        struct rtattr *a;
121
 
                        size_t l;
122
 
                        void *local = NULL, *address = NULL;
123
 
 
124
 
                        if (!NLMSG_OK(p, (size_t) bytes)) {
125
 
                                r = -EIO;
126
 
                                goto finish;
127
 
                        }
128
 
 
129
 
                        if (p->nlmsg_seq != seq)
130
 
                                continue;
131
 
 
132
 
                        if (p->nlmsg_type == NLMSG_DONE) {
133
 
                                r = 0;
134
 
                                goto finish;
135
 
                        }
136
 
 
137
 
                        if (p->nlmsg_type == NLMSG_ERROR) {
138
 
                                struct nlmsgerr *nlmsgerr;
139
 
 
140
 
                                nlmsgerr = NLMSG_DATA(p);
141
 
                                r = -nlmsgerr->error;
142
 
                                goto finish;
143
 
                        }
144
 
 
145
 
                        if (p->nlmsg_type != RTM_NEWADDR)
146
 
                                continue;
147
 
 
148
 
                        ifaddrmsg = NLMSG_DATA(p);
149
 
 
150
 
                        if (ifaddrmsg->ifa_family != AF_INET &&
151
 
                            ifaddrmsg->ifa_family != AF_INET6)
152
 
                                continue;
153
 
 
154
 
                        if (ifaddrmsg->ifa_scope == RT_SCOPE_HOST ||
155
 
                            ifaddrmsg->ifa_scope == RT_SCOPE_NOWHERE)
156
 
                                continue;
157
 
 
158
 
                        if (ifaddrmsg->ifa_flags & IFA_F_DEPRECATED)
159
 
                                continue;
160
 
 
161
 
                        l = NLMSG_PAYLOAD(p, sizeof(struct ifaddrmsg));
162
 
                        a = IFA_RTA(ifaddrmsg);
163
 
 
164
 
                        while (RTA_OK(a, l)) {
165
 
 
166
 
                                if (a->rta_type == IFA_ADDRESS)
167
 
                                        address = RTA_DATA(a);
168
 
                                else if (a->rta_type == IFA_LOCAL)
169
 
                                        local = RTA_DATA(a);
170
 
 
171
 
                                a = RTA_NEXT(a, l);
172
 
                        }
173
 
 
174
 
                        if (local)
175
 
                                address = local;
176
 
 
177
 
                        if (!address)
178
 
                                continue;
179
 
 
180
 
                        list = realloc(list, (n_list+1) * sizeof(struct address));
181
 
                        if (!list) {
182
 
                                r = -ENOMEM;
183
 
                                goto finish;
184
 
                        }
185
 
 
186
 
                        list[n_list].family = ifaddrmsg->ifa_family;
187
 
                        list[n_list].scope = ifaddrmsg->ifa_scope;
188
 
                        memcpy(list[n_list].address, address, ifaddrmsg->ifa_family == AF_INET ? 4 : 16);
189
 
                        list[n_list].ifindex = ifaddrmsg->ifa_index;
190
 
 
191
 
                        n_list++;
192
 
                }
193
 
        }
 
189
        while((r = read_reply(fd, &list, &n_list)) == 0)
 
190
                ;
194
191
 
195
192
finish:
196
193
        close(fd);
197
194
 
198
 
        if (r < 0)
 
195
        if (r < 0) {
199
196
                free(list);
200
 
        else {
201
 
                qsort(list, n_list, sizeof(struct address), address_compare);
202
 
 
203
 
                *_list = list;
204
 
                *_n_list = n_list;
 
197
                return r;
205
198
        }
206
199
 
207
 
        return r;
 
200
        qsort(list, n_list, sizeof(struct address), address_compare);
 
201
 
 
202
        *_list = list;
 
203
        *_n_list = n_list;
 
204
 
 
205
        return 0;
208
206
}