Statistics
| Branch: | Revision:

root / qemu-bridge-helper.c @ feature-archipelago

History | View | Annotate | Download (11.1 kB)

1 7b93fadf Corey Bryant
/*
2 7b93fadf Corey Bryant
 * QEMU Bridge Helper
3 7b93fadf Corey Bryant
 *
4 7b93fadf Corey Bryant
 * Copyright IBM, Corp. 2011
5 7b93fadf Corey Bryant
 *
6 7b93fadf Corey Bryant
 * Authors:
7 7b93fadf Corey Bryant
 * Anthony Liguori   <aliguori@us.ibm.com>
8 7b93fadf Corey Bryant
 * Richa Marwaha     <rmarwah@linux.vnet.ibm.com>
9 7b93fadf Corey Bryant
 * Corey Bryant      <coreyb@linux.vnet.ibm.com>
10 7b93fadf Corey Bryant
 *
11 7b93fadf Corey Bryant
 * This work is licensed under the terms of the GNU GPL, version 2.  See
12 7b93fadf Corey Bryant
 * the COPYING file in the top-level directory.
13 7b93fadf Corey Bryant
 *
14 7b93fadf Corey Bryant
 */
15 7b93fadf Corey Bryant
16 7b93fadf Corey Bryant
#include "config-host.h"
17 7b93fadf Corey Bryant
18 7b93fadf Corey Bryant
#include <stdio.h>
19 7b93fadf Corey Bryant
#include <errno.h>
20 7b93fadf Corey Bryant
#include <fcntl.h>
21 7b93fadf Corey Bryant
#include <unistd.h>
22 7b93fadf Corey Bryant
#include <string.h>
23 7b93fadf Corey Bryant
#include <stdlib.h>
24 7b93fadf Corey Bryant
#include <stdbool.h>
25 7b93fadf Corey Bryant
#include <ctype.h>
26 bdef79a2 Corey Bryant
#include <glib.h>
27 7b93fadf Corey Bryant
28 7b93fadf Corey Bryant
#include <sys/types.h>
29 7b93fadf Corey Bryant
#include <sys/ioctl.h>
30 7b93fadf Corey Bryant
#include <sys/socket.h>
31 7b93fadf Corey Bryant
#include <sys/un.h>
32 7b93fadf Corey Bryant
#include <sys/prctl.h>
33 7b93fadf Corey Bryant
34 7b93fadf Corey Bryant
#include <net/if.h>
35 7b93fadf Corey Bryant
36 7b93fadf Corey Bryant
#include <linux/sockios.h>
37 7b93fadf Corey Bryant
38 34309d2b Corey Bryant
#ifndef SIOCBRADDIF
39 34309d2b Corey Bryant
#include <linux/if_bridge.h>
40 34309d2b Corey Bryant
#endif
41 34309d2b Corey Bryant
42 1de7afc9 Paolo Bonzini
#include "qemu/queue.h"
43 bdef79a2 Corey Bryant
44 7b93fadf Corey Bryant
#include "net/tap-linux.h"
45 7b93fadf Corey Bryant
46 47e98658 Corey Bryant
#ifdef CONFIG_LIBCAP
47 47e98658 Corey Bryant
#include <cap-ng.h>
48 47e98658 Corey Bryant
#endif
49 47e98658 Corey Bryant
50 bdef79a2 Corey Bryant
#define DEFAULT_ACL_FILE CONFIG_QEMU_CONFDIR "/bridge.conf"
51 bdef79a2 Corey Bryant
52 bdef79a2 Corey Bryant
enum {
53 bdef79a2 Corey Bryant
    ACL_ALLOW = 0,
54 bdef79a2 Corey Bryant
    ACL_ALLOW_ALL,
55 bdef79a2 Corey Bryant
    ACL_DENY,
56 bdef79a2 Corey Bryant
    ACL_DENY_ALL,
57 bdef79a2 Corey Bryant
};
58 bdef79a2 Corey Bryant
59 bdef79a2 Corey Bryant
typedef struct ACLRule {
60 bdef79a2 Corey Bryant
    int type;
61 bdef79a2 Corey Bryant
    char iface[IFNAMSIZ];
62 bdef79a2 Corey Bryant
    QSIMPLEQ_ENTRY(ACLRule) entry;
63 bdef79a2 Corey Bryant
} ACLRule;
64 bdef79a2 Corey Bryant
65 bdef79a2 Corey Bryant
typedef QSIMPLEQ_HEAD(ACLList, ACLRule) ACLList;
66 bdef79a2 Corey Bryant
67 7b93fadf Corey Bryant
static void usage(void)
68 7b93fadf Corey Bryant
{
69 7b93fadf Corey Bryant
    fprintf(stderr,
70 7b93fadf Corey Bryant
            "Usage: qemu-bridge-helper [--use-vnet] --br=bridge --fd=unixfd\n");
71 7b93fadf Corey Bryant
}
72 7b93fadf Corey Bryant
73 bdef79a2 Corey Bryant
static int parse_acl_file(const char *filename, ACLList *acl_list)
74 bdef79a2 Corey Bryant
{
75 bdef79a2 Corey Bryant
    FILE *f;
76 bdef79a2 Corey Bryant
    char line[4096];
77 bdef79a2 Corey Bryant
    ACLRule *acl_rule;
78 bdef79a2 Corey Bryant
79 bdef79a2 Corey Bryant
    f = fopen(filename, "r");
80 bdef79a2 Corey Bryant
    if (f == NULL) {
81 bdef79a2 Corey Bryant
        return -1;
82 bdef79a2 Corey Bryant
    }
83 bdef79a2 Corey Bryant
84 bdef79a2 Corey Bryant
    while (fgets(line, sizeof(line), f) != NULL) {
85 bdef79a2 Corey Bryant
        char *ptr = line;
86 bdef79a2 Corey Bryant
        char *cmd, *arg, *argend;
87 bdef79a2 Corey Bryant
88 bdef79a2 Corey Bryant
        while (isspace(*ptr)) {
89 bdef79a2 Corey Bryant
            ptr++;
90 bdef79a2 Corey Bryant
        }
91 bdef79a2 Corey Bryant
92 bdef79a2 Corey Bryant
        /* skip comments and empty lines */
93 bdef79a2 Corey Bryant
        if (*ptr == '#' || *ptr == 0) {
94 bdef79a2 Corey Bryant
            continue;
95 bdef79a2 Corey Bryant
        }
96 bdef79a2 Corey Bryant
97 bdef79a2 Corey Bryant
        cmd = ptr;
98 bdef79a2 Corey Bryant
        arg = strchr(cmd, ' ');
99 bdef79a2 Corey Bryant
        if (arg == NULL) {
100 bdef79a2 Corey Bryant
            arg = strchr(cmd, '\t');
101 bdef79a2 Corey Bryant
        }
102 bdef79a2 Corey Bryant
103 bdef79a2 Corey Bryant
        if (arg == NULL) {
104 bdef79a2 Corey Bryant
            fprintf(stderr, "Invalid config line:\n  %s\n", line);
105 bdef79a2 Corey Bryant
            fclose(f);
106 bdef79a2 Corey Bryant
            errno = EINVAL;
107 bdef79a2 Corey Bryant
            return -1;
108 bdef79a2 Corey Bryant
        }
109 bdef79a2 Corey Bryant
110 bdef79a2 Corey Bryant
        *arg = 0;
111 bdef79a2 Corey Bryant
        arg++;
112 bdef79a2 Corey Bryant
        while (isspace(*arg)) {
113 bdef79a2 Corey Bryant
            arg++;
114 bdef79a2 Corey Bryant
        }
115 bdef79a2 Corey Bryant
116 bdef79a2 Corey Bryant
        argend = arg + strlen(arg);
117 bdef79a2 Corey Bryant
        while (arg != argend && isspace(*(argend - 1))) {
118 bdef79a2 Corey Bryant
            argend--;
119 bdef79a2 Corey Bryant
        }
120 bdef79a2 Corey Bryant
        *argend = 0;
121 bdef79a2 Corey Bryant
122 bdef79a2 Corey Bryant
        if (strcmp(cmd, "deny") == 0) {
123 bdef79a2 Corey Bryant
            acl_rule = g_malloc(sizeof(*acl_rule));
124 bdef79a2 Corey Bryant
            if (strcmp(arg, "all") == 0) {
125 bdef79a2 Corey Bryant
                acl_rule->type = ACL_DENY_ALL;
126 bdef79a2 Corey Bryant
            } else {
127 bdef79a2 Corey Bryant
                acl_rule->type = ACL_DENY;
128 bdef79a2 Corey Bryant
                snprintf(acl_rule->iface, IFNAMSIZ, "%s", arg);
129 bdef79a2 Corey Bryant
            }
130 bdef79a2 Corey Bryant
            QSIMPLEQ_INSERT_TAIL(acl_list, acl_rule, entry);
131 bdef79a2 Corey Bryant
        } else if (strcmp(cmd, "allow") == 0) {
132 bdef79a2 Corey Bryant
            acl_rule = g_malloc(sizeof(*acl_rule));
133 bdef79a2 Corey Bryant
            if (strcmp(arg, "all") == 0) {
134 bdef79a2 Corey Bryant
                acl_rule->type = ACL_ALLOW_ALL;
135 bdef79a2 Corey Bryant
            } else {
136 bdef79a2 Corey Bryant
                acl_rule->type = ACL_ALLOW;
137 bdef79a2 Corey Bryant
                snprintf(acl_rule->iface, IFNAMSIZ, "%s", arg);
138 bdef79a2 Corey Bryant
            }
139 bdef79a2 Corey Bryant
            QSIMPLEQ_INSERT_TAIL(acl_list, acl_rule, entry);
140 bdef79a2 Corey Bryant
        } else if (strcmp(cmd, "include") == 0) {
141 bdef79a2 Corey Bryant
            /* ignore errors */
142 bdef79a2 Corey Bryant
            parse_acl_file(arg, acl_list);
143 bdef79a2 Corey Bryant
        } else {
144 bdef79a2 Corey Bryant
            fprintf(stderr, "Unknown command `%s'\n", cmd);
145 bdef79a2 Corey Bryant
            fclose(f);
146 bdef79a2 Corey Bryant
            errno = EINVAL;
147 bdef79a2 Corey Bryant
            return -1;
148 bdef79a2 Corey Bryant
        }
149 bdef79a2 Corey Bryant
    }
150 bdef79a2 Corey Bryant
151 bdef79a2 Corey Bryant
    fclose(f);
152 bdef79a2 Corey Bryant
153 bdef79a2 Corey Bryant
    return 0;
154 bdef79a2 Corey Bryant
}
155 bdef79a2 Corey Bryant
156 7b93fadf Corey Bryant
static bool has_vnet_hdr(int fd)
157 7b93fadf Corey Bryant
{
158 7b93fadf Corey Bryant
    unsigned int features = 0;
159 7b93fadf Corey Bryant
160 7b93fadf Corey Bryant
    if (ioctl(fd, TUNGETFEATURES, &features) == -1) {
161 7b93fadf Corey Bryant
        return false;
162 7b93fadf Corey Bryant
    }
163 7b93fadf Corey Bryant
164 7b93fadf Corey Bryant
    if (!(features & IFF_VNET_HDR)) {
165 7b93fadf Corey Bryant
        return false;
166 7b93fadf Corey Bryant
    }
167 7b93fadf Corey Bryant
168 7b93fadf Corey Bryant
    return true;
169 7b93fadf Corey Bryant
}
170 7b93fadf Corey Bryant
171 7b93fadf Corey Bryant
static void prep_ifreq(struct ifreq *ifr, const char *ifname)
172 7b93fadf Corey Bryant
{
173 7b93fadf Corey Bryant
    memset(ifr, 0, sizeof(*ifr));
174 7b93fadf Corey Bryant
    snprintf(ifr->ifr_name, IFNAMSIZ, "%s", ifname);
175 7b93fadf Corey Bryant
}
176 7b93fadf Corey Bryant
177 7b93fadf Corey Bryant
static int send_fd(int c, int fd)
178 7b93fadf Corey Bryant
{
179 7b93fadf Corey Bryant
    char msgbuf[CMSG_SPACE(sizeof(fd))];
180 7b93fadf Corey Bryant
    struct msghdr msg = {
181 7b93fadf Corey Bryant
        .msg_control = msgbuf,
182 7b93fadf Corey Bryant
        .msg_controllen = sizeof(msgbuf),
183 7b93fadf Corey Bryant
    };
184 7b93fadf Corey Bryant
    struct cmsghdr *cmsg;
185 7b93fadf Corey Bryant
    struct iovec iov;
186 7b93fadf Corey Bryant
    char req[1] = { 0x00 };
187 7b93fadf Corey Bryant
188 7b93fadf Corey Bryant
    cmsg = CMSG_FIRSTHDR(&msg);
189 7b93fadf Corey Bryant
    cmsg->cmsg_level = SOL_SOCKET;
190 7b93fadf Corey Bryant
    cmsg->cmsg_type = SCM_RIGHTS;
191 7b93fadf Corey Bryant
    cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
192 7b93fadf Corey Bryant
    msg.msg_controllen = cmsg->cmsg_len;
193 7b93fadf Corey Bryant
194 7b93fadf Corey Bryant
    iov.iov_base = req;
195 7b93fadf Corey Bryant
    iov.iov_len = sizeof(req);
196 7b93fadf Corey Bryant
197 7b93fadf Corey Bryant
    msg.msg_iov = &iov;
198 7b93fadf Corey Bryant
    msg.msg_iovlen = 1;
199 7b93fadf Corey Bryant
    memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
200 7b93fadf Corey Bryant
201 7b93fadf Corey Bryant
    return sendmsg(c, &msg, 0);
202 7b93fadf Corey Bryant
}
203 7b93fadf Corey Bryant
204 47e98658 Corey Bryant
#ifdef CONFIG_LIBCAP
205 47e98658 Corey Bryant
static int drop_privileges(void)
206 47e98658 Corey Bryant
{
207 47e98658 Corey Bryant
    /* clear all capabilities */
208 47e98658 Corey Bryant
    capng_clear(CAPNG_SELECT_BOTH);
209 47e98658 Corey Bryant
210 47e98658 Corey Bryant
    if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
211 47e98658 Corey Bryant
                     CAP_NET_ADMIN) < 0) {
212 47e98658 Corey Bryant
        return -1;
213 47e98658 Corey Bryant
    }
214 47e98658 Corey Bryant
215 47e98658 Corey Bryant
    /* change to calling user's real uid and gid, retaining supplemental
216 47e98658 Corey Bryant
     * groups and CAP_NET_ADMIN */
217 47e98658 Corey Bryant
    if (capng_change_id(getuid(), getgid(), CAPNG_CLEAR_BOUNDING)) {
218 47e98658 Corey Bryant
        return -1;
219 47e98658 Corey Bryant
    }
220 47e98658 Corey Bryant
221 47e98658 Corey Bryant
    return 0;
222 47e98658 Corey Bryant
}
223 47e98658 Corey Bryant
#endif
224 47e98658 Corey Bryant
225 7b93fadf Corey Bryant
int main(int argc, char **argv)
226 7b93fadf Corey Bryant
{
227 7b93fadf Corey Bryant
    struct ifreq ifr;
228 34309d2b Corey Bryant
#ifndef SIOCBRADDIF
229 34309d2b Corey Bryant
    unsigned long ifargs[4];
230 34309d2b Corey Bryant
#endif
231 34309d2b Corey Bryant
    int ifindex;
232 7b93fadf Corey Bryant
    int fd, ctlfd, unixfd = -1;
233 7b93fadf Corey Bryant
    int use_vnet = 0;
234 7b93fadf Corey Bryant
    int mtu;
235 7b93fadf Corey Bryant
    const char *bridge = NULL;
236 7b93fadf Corey Bryant
    char iface[IFNAMSIZ];
237 7b93fadf Corey Bryant
    int index;
238 bdef79a2 Corey Bryant
    ACLRule *acl_rule;
239 bdef79a2 Corey Bryant
    ACLList acl_list;
240 bdef79a2 Corey Bryant
    int access_allowed, access_denied;
241 7b93fadf Corey Bryant
    int ret = EXIT_SUCCESS;
242 7b93fadf Corey Bryant
243 47e98658 Corey Bryant
#ifdef CONFIG_LIBCAP
244 47e98658 Corey Bryant
    /* if we're run from an suid binary, immediately drop privileges preserving
245 47e98658 Corey Bryant
     * cap_net_admin */
246 47e98658 Corey Bryant
    if (geteuid() == 0 && getuid() != geteuid()) {
247 47e98658 Corey Bryant
        if (drop_privileges() == -1) {
248 47e98658 Corey Bryant
            fprintf(stderr, "failed to drop privileges\n");
249 47e98658 Corey Bryant
            return 1;
250 47e98658 Corey Bryant
        }
251 47e98658 Corey Bryant
    }
252 47e98658 Corey Bryant
#endif
253 47e98658 Corey Bryant
254 7b93fadf Corey Bryant
    /* parse arguments */
255 7b93fadf Corey Bryant
    for (index = 1; index < argc; index++) {
256 7b93fadf Corey Bryant
        if (strcmp(argv[index], "--use-vnet") == 0) {
257 7b93fadf Corey Bryant
            use_vnet = 1;
258 7b93fadf Corey Bryant
        } else if (strncmp(argv[index], "--br=", 5) == 0) {
259 7b93fadf Corey Bryant
            bridge = &argv[index][5];
260 7b93fadf Corey Bryant
        } else if (strncmp(argv[index], "--fd=", 5) == 0) {
261 7b93fadf Corey Bryant
            unixfd = atoi(&argv[index][5]);
262 7b93fadf Corey Bryant
        } else {
263 7b93fadf Corey Bryant
            usage();
264 7b93fadf Corey Bryant
            return EXIT_FAILURE;
265 7b93fadf Corey Bryant
        }
266 7b93fadf Corey Bryant
    }
267 7b93fadf Corey Bryant
268 7b93fadf Corey Bryant
    if (bridge == NULL || unixfd == -1) {
269 7b93fadf Corey Bryant
        usage();
270 7b93fadf Corey Bryant
        return EXIT_FAILURE;
271 7b93fadf Corey Bryant
    }
272 7b93fadf Corey Bryant
273 bdef79a2 Corey Bryant
    /* parse default acl file */
274 bdef79a2 Corey Bryant
    QSIMPLEQ_INIT(&acl_list);
275 bdef79a2 Corey Bryant
    if (parse_acl_file(DEFAULT_ACL_FILE, &acl_list) == -1) {
276 bdef79a2 Corey Bryant
        fprintf(stderr, "failed to parse default acl file `%s'\n",
277 bdef79a2 Corey Bryant
                DEFAULT_ACL_FILE);
278 bdef79a2 Corey Bryant
        ret = EXIT_FAILURE;
279 bdef79a2 Corey Bryant
        goto cleanup;
280 bdef79a2 Corey Bryant
    }
281 bdef79a2 Corey Bryant
282 bdef79a2 Corey Bryant
    /* validate bridge against acl -- default policy is to deny
283 bdef79a2 Corey Bryant
     * according acl policy if we have a deny and allow both
284 bdef79a2 Corey Bryant
     * then deny should always win over allow
285 bdef79a2 Corey Bryant
     */
286 bdef79a2 Corey Bryant
    access_allowed = 0;
287 bdef79a2 Corey Bryant
    access_denied = 0;
288 bdef79a2 Corey Bryant
    QSIMPLEQ_FOREACH(acl_rule, &acl_list, entry) {
289 bdef79a2 Corey Bryant
        switch (acl_rule->type) {
290 bdef79a2 Corey Bryant
        case ACL_ALLOW_ALL:
291 bdef79a2 Corey Bryant
            access_allowed = 1;
292 bdef79a2 Corey Bryant
            break;
293 bdef79a2 Corey Bryant
        case ACL_ALLOW:
294 bdef79a2 Corey Bryant
            if (strcmp(bridge, acl_rule->iface) == 0) {
295 bdef79a2 Corey Bryant
                access_allowed = 1;
296 bdef79a2 Corey Bryant
            }
297 bdef79a2 Corey Bryant
            break;
298 bdef79a2 Corey Bryant
        case ACL_DENY_ALL:
299 bdef79a2 Corey Bryant
            access_denied = 1;
300 bdef79a2 Corey Bryant
            break;
301 bdef79a2 Corey Bryant
        case ACL_DENY:
302 bdef79a2 Corey Bryant
            if (strcmp(bridge, acl_rule->iface) == 0) {
303 bdef79a2 Corey Bryant
                access_denied = 1;
304 bdef79a2 Corey Bryant
            }
305 bdef79a2 Corey Bryant
            break;
306 bdef79a2 Corey Bryant
        }
307 bdef79a2 Corey Bryant
    }
308 bdef79a2 Corey Bryant
309 bdef79a2 Corey Bryant
    if ((access_allowed == 0) || (access_denied == 1)) {
310 bdef79a2 Corey Bryant
        fprintf(stderr, "access denied by acl file\n");
311 bdef79a2 Corey Bryant
        ret = EXIT_FAILURE;
312 bdef79a2 Corey Bryant
        goto cleanup;
313 bdef79a2 Corey Bryant
    }
314 bdef79a2 Corey Bryant
315 7b93fadf Corey Bryant
    /* open a socket to use to control the network interfaces */
316 7b93fadf Corey Bryant
    ctlfd = socket(AF_INET, SOCK_STREAM, 0);
317 7b93fadf Corey Bryant
    if (ctlfd == -1) {
318 7b93fadf Corey Bryant
        fprintf(stderr, "failed to open control socket: %s\n", strerror(errno));
319 7b93fadf Corey Bryant
        ret = EXIT_FAILURE;
320 7b93fadf Corey Bryant
        goto cleanup;
321 7b93fadf Corey Bryant
    }
322 7b93fadf Corey Bryant
323 7b93fadf Corey Bryant
    /* open the tap device */
324 7b93fadf Corey Bryant
    fd = open("/dev/net/tun", O_RDWR);
325 7b93fadf Corey Bryant
    if (fd == -1) {
326 7b93fadf Corey Bryant
        fprintf(stderr, "failed to open /dev/net/tun: %s\n", strerror(errno));
327 7b93fadf Corey Bryant
        ret = EXIT_FAILURE;
328 7b93fadf Corey Bryant
        goto cleanup;
329 7b93fadf Corey Bryant
    }
330 7b93fadf Corey Bryant
331 7b93fadf Corey Bryant
    /* request a tap device, disable PI, and add vnet header support if
332 7b93fadf Corey Bryant
     * requested and it's available. */
333 7b93fadf Corey Bryant
    prep_ifreq(&ifr, "tap%d");
334 7b93fadf Corey Bryant
    ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
335 7b93fadf Corey Bryant
    if (use_vnet && has_vnet_hdr(fd)) {
336 7b93fadf Corey Bryant
        ifr.ifr_flags |= IFF_VNET_HDR;
337 7b93fadf Corey Bryant
    }
338 7b93fadf Corey Bryant
339 7b93fadf Corey Bryant
    if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
340 7b93fadf Corey Bryant
        fprintf(stderr, "failed to create tun device: %s\n", strerror(errno));
341 7b93fadf Corey Bryant
        ret = EXIT_FAILURE;
342 7b93fadf Corey Bryant
        goto cleanup;
343 7b93fadf Corey Bryant
    }
344 7b93fadf Corey Bryant
345 7b93fadf Corey Bryant
    /* save tap device name */
346 7b93fadf Corey Bryant
    snprintf(iface, sizeof(iface), "%s", ifr.ifr_name);
347 7b93fadf Corey Bryant
348 7b93fadf Corey Bryant
    /* get the mtu of the bridge */
349 7b93fadf Corey Bryant
    prep_ifreq(&ifr, bridge);
350 7b93fadf Corey Bryant
    if (ioctl(ctlfd, SIOCGIFMTU, &ifr) == -1) {
351 7b93fadf Corey Bryant
        fprintf(stderr, "failed to get mtu of bridge `%s': %s\n",
352 7b93fadf Corey Bryant
                bridge, strerror(errno));
353 7b93fadf Corey Bryant
        ret = EXIT_FAILURE;
354 7b93fadf Corey Bryant
        goto cleanup;
355 7b93fadf Corey Bryant
    }
356 7b93fadf Corey Bryant
357 7b93fadf Corey Bryant
    /* save mtu */
358 7b93fadf Corey Bryant
    mtu = ifr.ifr_mtu;
359 7b93fadf Corey Bryant
360 7b93fadf Corey Bryant
    /* set the mtu of the interface based on the bridge */
361 7b93fadf Corey Bryant
    prep_ifreq(&ifr, iface);
362 7b93fadf Corey Bryant
    ifr.ifr_mtu = mtu;
363 7b93fadf Corey Bryant
    if (ioctl(ctlfd, SIOCSIFMTU, &ifr) == -1) {
364 7b93fadf Corey Bryant
        fprintf(stderr, "failed to set mtu of device `%s' to %d: %s\n",
365 7b93fadf Corey Bryant
                iface, mtu, strerror(errno));
366 7b93fadf Corey Bryant
        ret = EXIT_FAILURE;
367 7b93fadf Corey Bryant
        goto cleanup;
368 7b93fadf Corey Bryant
    }
369 7b93fadf Corey Bryant
370 226ecabf Paolo Bonzini
    /* Linux uses the lowest enslaved MAC address as the MAC address of
371 226ecabf Paolo Bonzini
     * the bridge.  Set MAC address to a high value so that it doesn't
372 226ecabf Paolo Bonzini
     * affect the MAC address of the bridge.
373 226ecabf Paolo Bonzini
     */
374 226ecabf Paolo Bonzini
    if (ioctl(ctlfd, SIOCGIFHWADDR, &ifr) < 0) {
375 226ecabf Paolo Bonzini
        fprintf(stderr, "failed to get MAC address of device `%s': %s\n",
376 226ecabf Paolo Bonzini
                iface, strerror(errno));
377 226ecabf Paolo Bonzini
        ret = EXIT_FAILURE;
378 226ecabf Paolo Bonzini
        goto cleanup;
379 226ecabf Paolo Bonzini
    }
380 226ecabf Paolo Bonzini
    ifr.ifr_hwaddr.sa_data[0] = 0xFE;
381 226ecabf Paolo Bonzini
    if (ioctl(ctlfd, SIOCSIFHWADDR, &ifr) < 0) {
382 226ecabf Paolo Bonzini
        fprintf(stderr, "failed to set MAC address of device `%s': %s\n",
383 226ecabf Paolo Bonzini
                iface, strerror(errno));
384 226ecabf Paolo Bonzini
        ret = EXIT_FAILURE;
385 226ecabf Paolo Bonzini
        goto cleanup;
386 226ecabf Paolo Bonzini
    }
387 226ecabf Paolo Bonzini
388 7b93fadf Corey Bryant
    /* add the interface to the bridge */
389 7b93fadf Corey Bryant
    prep_ifreq(&ifr, bridge);
390 34309d2b Corey Bryant
    ifindex = if_nametoindex(iface);
391 34309d2b Corey Bryant
#ifndef SIOCBRADDIF
392 34309d2b Corey Bryant
    ifargs[0] = BRCTL_ADD_IF;
393 34309d2b Corey Bryant
    ifargs[1] = ifindex;
394 34309d2b Corey Bryant
    ifargs[2] = 0;
395 34309d2b Corey Bryant
    ifargs[3] = 0;
396 34309d2b Corey Bryant
    ifr.ifr_data = (void *)ifargs;
397 34309d2b Corey Bryant
    ret = ioctl(ctlfd, SIOCDEVPRIVATE, &ifr);
398 34309d2b Corey Bryant
#else
399 34309d2b Corey Bryant
    ifr.ifr_ifindex = ifindex;
400 34309d2b Corey Bryant
    ret = ioctl(ctlfd, SIOCBRADDIF, &ifr);
401 34309d2b Corey Bryant
#endif
402 34309d2b Corey Bryant
    if (ret == -1) {
403 7b93fadf Corey Bryant
        fprintf(stderr, "failed to add interface `%s' to bridge `%s': %s\n",
404 7b93fadf Corey Bryant
                iface, bridge, strerror(errno));
405 7b93fadf Corey Bryant
        ret = EXIT_FAILURE;
406 7b93fadf Corey Bryant
        goto cleanup;
407 7b93fadf Corey Bryant
    }
408 7b93fadf Corey Bryant
409 7b93fadf Corey Bryant
    /* bring the interface up */
410 7b93fadf Corey Bryant
    prep_ifreq(&ifr, iface);
411 7b93fadf Corey Bryant
    if (ioctl(ctlfd, SIOCGIFFLAGS, &ifr) == -1) {
412 7b93fadf Corey Bryant
        fprintf(stderr, "failed to get interface flags for `%s': %s\n",
413 7b93fadf Corey Bryant
                iface, strerror(errno));
414 7b93fadf Corey Bryant
        ret = EXIT_FAILURE;
415 7b93fadf Corey Bryant
        goto cleanup;
416 7b93fadf Corey Bryant
    }
417 7b93fadf Corey Bryant
418 7b93fadf Corey Bryant
    ifr.ifr_flags |= IFF_UP;
419 7b93fadf Corey Bryant
    if (ioctl(ctlfd, SIOCSIFFLAGS, &ifr) == -1) {
420 7b93fadf Corey Bryant
        fprintf(stderr, "failed to bring up interface `%s': %s\n",
421 7b93fadf Corey Bryant
                iface, strerror(errno));
422 7b93fadf Corey Bryant
        ret = EXIT_FAILURE;
423 7b93fadf Corey Bryant
        goto cleanup;
424 7b93fadf Corey Bryant
    }
425 7b93fadf Corey Bryant
426 7b93fadf Corey Bryant
    /* write fd to the domain socket */
427 7b93fadf Corey Bryant
    if (send_fd(unixfd, fd) == -1) {
428 7b93fadf Corey Bryant
        fprintf(stderr, "failed to write fd to unix socket: %s\n",
429 7b93fadf Corey Bryant
                strerror(errno));
430 7b93fadf Corey Bryant
        ret = EXIT_FAILURE;
431 7b93fadf Corey Bryant
        goto cleanup;
432 7b93fadf Corey Bryant
    }
433 7b93fadf Corey Bryant
434 7b93fadf Corey Bryant
    /* ... */
435 7b93fadf Corey Bryant
436 7b93fadf Corey Bryant
    /* profit! */
437 7b93fadf Corey Bryant
438 7b93fadf Corey Bryant
cleanup:
439 7b93fadf Corey Bryant
440 bdef79a2 Corey Bryant
    while ((acl_rule = QSIMPLEQ_FIRST(&acl_list)) != NULL) {
441 bdef79a2 Corey Bryant
        QSIMPLEQ_REMOVE_HEAD(&acl_list, entry);
442 bdef79a2 Corey Bryant
        g_free(acl_rule);
443 bdef79a2 Corey Bryant
    }
444 bdef79a2 Corey Bryant
445 7b93fadf Corey Bryant
    return ret;
446 7b93fadf Corey Bryant
}