1 /* $NetBSD: af_inetany.c,v 1.12 2008/07/02 07:44:14 dyoung Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 David Young. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 #ifndef lint 30 __RCSID("$NetBSD: af_inetany.c,v 1.12 2008/07/02 07:44:14 dyoung Exp $"); 31 #endif /* not lint */ 32 33 #include <sys/param.h> 34 #include <sys/ioctl.h> 35 #include <sys/socket.h> 36 37 #include <net/if.h> 38 #include <netinet/in.h> 39 #include <netinet/in_var.h> 40 #include <netinet6/nd6.h> 41 42 #include <arpa/inet.h> 43 44 #include <assert.h> 45 #include <err.h> 46 #include <errno.h> 47 #include <ifaddrs.h> 48 #include <netdb.h> 49 #include <string.h> 50 #include <stdlib.h> 51 #include <stdio.h> 52 #include <util.h> 53 54 #include "env.h" 55 #include "extern.h" 56 #include "af_inetany.h" 57 58 static void * 59 loadbuf(const struct apbuf *b, const struct paddr_prefix *pfx) 60 { 61 return memcpy(b->buf, &pfx->pfx_addr, 62 MIN(b->buflen, pfx->pfx_addr.sa_len)); 63 } 64 65 void 66 commit_address(prop_dictionary_t env, prop_dictionary_t oenv, 67 const struct afparam *param) 68 { 69 const char *ifname; 70 int af, rc, s; 71 bool alias, delete, replace; 72 prop_data_t d; 73 const struct paddr_prefix *addr, *brd, *dst, *mask; 74 unsigned short flags; 75 76 if ((af = getaf(env)) == -1) 77 af = AF_INET; 78 79 if ((s = getsock(af)) == -1) 80 err(EXIT_FAILURE, "%s: getsock", __func__); 81 82 if ((ifname = getifinfo(env, oenv, &flags)) == NULL) 83 return; 84 85 strlcpy(param->name[0].buf, ifname, param->name[0].buflen); 86 strlcpy(param->name[1].buf, ifname, param->name[1].buflen); 87 88 if ((d = (prop_data_t)prop_dictionary_get(env, "address")) != NULL) 89 addr = prop_data_data_nocopy(d); 90 else if (!prop_dictionary_get_bool(env, "alias", &alias) || alias || 91 param->gifaddr.cmd == 0) 92 return; 93 else if (ioctl(s, param->gifaddr.cmd, param->dgreq.buf) == -1) 94 err(EXIT_FAILURE, param->gifaddr.desc); 95 else if (ioctl(s, param->difaddr.cmd, param->dgreq.buf) == -1) 96 err(EXIT_FAILURE, param->difaddr.desc); 97 else 98 return; 99 100 if ((d = (prop_data_t)prop_dictionary_get(env, "dst")) != NULL) 101 dst = prop_data_data_nocopy(d); 102 else 103 dst = NULL; 104 105 if ((d = (prop_data_t)prop_dictionary_get(env, "netmask")) != NULL) 106 mask = prop_data_data_nocopy(d); 107 else 108 mask = NULL; 109 110 if ((d = (prop_data_t)prop_dictionary_get(env, "broadcast")) != NULL) 111 brd = prop_data_data_nocopy(d); 112 else 113 brd = NULL; 114 115 if (!prop_dictionary_get_bool(env, "alias", &alias)) { 116 delete = false; 117 replace = (param->gifaddr.cmd != 0); 118 } else { 119 replace = false; 120 delete = !alias; 121 } 122 123 loadbuf(¶m->addr, addr); 124 125 /* TBD: read matching ifaddr from kernel, use the netmask as default 126 * TBD: handle preference 127 */ 128 switch (flags & (IFF_BROADCAST|IFF_POINTOPOINT)) { 129 case IFF_BROADCAST: 130 if (brd != NULL) 131 loadbuf(¶m->brd, brd); 132 /*FALLTHROUGH*/ 133 case 0: 134 break; 135 case IFF_POINTOPOINT: 136 if (brd != NULL) { 137 errx(EXIT_FAILURE, "%s is not a broadcast interface", 138 ifname); 139 } 140 if (dst != NULL) 141 loadbuf(¶m->dst, dst); 142 break; 143 case IFF_BROADCAST|IFF_POINTOPOINT: 144 errx(EXIT_FAILURE, "unsupported interface flags"); 145 } 146 if (param->mask.buf == NULL) { 147 if (mask != NULL) 148 errx(EXIT_FAILURE, "netmask not supported"); 149 } else if (mask != NULL) 150 loadbuf(¶m->mask, mask); 151 else if (param->defmask.buf != NULL) { 152 memcpy(param->mask.buf, param->defmask.buf, 153 MIN(param->mask.buflen, param->defmask.buflen)); 154 } 155 if (replace) { 156 if (ioctl(s, param->gifaddr.cmd, param->dgreq.buf) == 0) { 157 rc = ioctl(s, param->difaddr.cmd, param->dgreq.buf); 158 if (rc == -1) 159 err(EXIT_FAILURE, param->difaddr.desc); 160 } else if (errno == EADDRNOTAVAIL) 161 ; /* No address was assigned yet. */ 162 else 163 err(EXIT_FAILURE, param->gifaddr.desc); 164 } else if (delete) { 165 loadbuf(¶m->dgaddr, addr); 166 if (ioctl(s, param->difaddr.cmd, param->dgreq.buf) == -1) 167 err(EXIT_FAILURE, param->difaddr.desc); 168 return; 169 } 170 if (param->pre_aifaddr != NULL && 171 (*param->pre_aifaddr)(env, param) == -1) 172 err(EXIT_FAILURE, "pre-%s", param->aifaddr.desc); 173 if (ioctl(s, param->aifaddr.cmd, param->req.buf) == -1) 174 err(EXIT_FAILURE, param->aifaddr.desc); 175 } 176